Skip to main content
Version: 1.2

AWS RDS

Provision Amazon RDS for PostgreSQL, grant Hub a database role that authenticates with AWS IAM, then record the resulting endpoint and region for the install.

IAM authentication is the recommended path for self-hosted Hub on AWS. Rather than storing a static database password in your cluster, the hub-core Pods exchange a short-lived RDS auth token per database connection, using credentials from IAM Roles for Service Accounts (IRSA) or EKS Pod Identity.

If you can't use IAM in your environment, review the password-auth fallback instructions.

Prerequisites​

Before you begin, have the following ready:

  • An AWS account with permissions to create RDS instances, IAM roles, IAM policies, and (if you don't already have one) an OIDC provider for your EKS cluster.
  • A Kubernetes cluster running on AWS with a working AWS workload-identity mechanism: either IAM Roles for Service Accounts on EKS or EKS Pod Identity. Self-managed clusters can use IRSA as long as the API server's service-account-issuer is registered as an IAM OIDC provider.
  • psql (or another PostgreSQL client) installed locally, reachable to the RDS instance for the one-time bootstrap. A bastion or VPN is fine.
note

This page assumes you have already read the self-hosted overview and the database overview. It does not repeat generic Postgres requirements covered there.

Provision RDS​

Provision the database with whichever IaC tool you already use. This section lists only the settings that matter for Hub.

Read these AWS guides end-to-end before provisioning:

When you create the instance, set the following:

  • Engine: PostgreSQL 18 or newer.
  • IAM database authentication: enabled. This setting works as a per-instance flag. You must enable it at the instance level before you can use it for any single database or role.
  • Network: place the instance in private subnets and attach a security group that allows inbound TCP 5432 from the security group attached to the worker nodes that run hub-core.
  • TLS: RDS terminates TLS by default. Note the CA bundle you need to trust, since RDS rotates these on a published schedule.

Record three values once the instance is available:

  • the RDS endpoint hostname (for example,hub.cluster-xxxx.us-east-1.rds.amazonaws.com).
  • the instance's DbiResourceId (a string starting with db-…). You can find it in the RDS console under the instance's Configuration tab, or via aws rds describe-db-instances. An IAM policy you create later targets this ID, not the instance name.
  • the AWS region (for example, us-east-1).
warning

Enabling IAM database authentication on an existing instance triggers a reboot, so schedule it during a maintenance window.

Configure IAM authentication​

IAM auth for RDS has three sides that must agree:

  1. An IAM role the hub-core Pod can assume.
  2. A policy on that role granting rds-db:connect for the database user Hub logs in as.
  3. A PostgreSQL role with the same name as the IAM user, granted the rds_iam role inside the database.

Create the database role​

Connect to the instance as the master user and create the role Hub uses. This role needs the rds_iam grant so RDS accepts IAM-issued tokens for it, as described in Creating a database account using IAM authentication. It also needs ownership of the Hub database so migrations can create and alter objects.

CREATE DATABASE hub;
CREATE USER hub;
GRANT rds_iam TO hub;
GRANT ALL PRIVILEGES ON DATABASE hub TO hub;
\c hub
GRANT ALL ON SCHEMA public TO hub;

Then, as the master user, create the hstore extension in a dedicated extensions schema, let hub use the schema, and put the schema on the database's search path. The migrations need all three, and hub can't move hstore into extensions itself because it isn't a superuser:

\c hub
CREATE SCHEMA IF NOT EXISTS extensions;
GRANT USAGE ON SCHEMA extensions TO hub;
CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA extensions;
ALTER DATABASE hub SET search_path TO "$user", public, extensions;
note

rds_iam and password authentication are mutually exclusive on RDS. A role granted rds_iam can't also log in with a password. Don't set a password on hub.

Create the IAM policy​

Follow Creating and using an IAM policy for IAM database access. Hub needs one statement, allowing rds-db:connect on the hub database role:

FieldValue for Hub
Actionrds-db:connect
Resourcearn:aws:rds-db:<region>:<account-id>:dbuser:<dbi-resource-id>/hub

The final segment of the resource ARN is the database role name, hub, and <dbi-resource-id> is the db-… string you recorded above, not the instance name.

Record the resulting policy ARN. You attach it to the role in the next section.

Bind the policy to the hub-core ServiceAccounts​

Attach the policy to an IAM role the hub-core Pods can assume. AWS offers two mechanisms. IRSA works on any EKS cluster with an IAM OIDC provider. Pod Identity is simpler to manage where it's available.

Whichever you pick, the role identifies Pods by their Kubernetes ServiceAccount. Two Hub workloads connect to the database with IAM: the hub-core Deployment and the migration Job that applies the schema. The chart creates a ServiceAccount for each, so these values are what AWS's procedure needs:

What the AWS procedure asks forValue for Hub
Namespacehub, or the namespace you install the release into
ServiceAccount nameshub-core and hub-core-migrate
IRSA trust policy sub conditionsystem:serviceaccount:hub:hub-core and system:serviceaccount:hub:hub-core-migrate
IRSA trust policy aud conditionsts.amazonaws.com

Option A: IAM roles for service accounts (IRSA)​

Follow Assign IAM roles to Kubernetes service accounts, using the subject and audience conditions from the table above. Allow both subjects in the trust policy. If your cluster's OIDC issuer isn't registered with IAM yet, do Create an IAM OIDC provider first.

You then annotate both ServiceAccounts with the role ARN through Helm values, shown in the next section.

Option B: EKS pod identity​

Follow Assign an IAM role to a Kubernetes service account, creating one association against namespace hub and ServiceAccount hub-core, and a second against ServiceAccount hub-core-migrate. Create both associations before you install Hub. The migration Job starts during the install and fails if it can't get credentials.

With Pod Identity the ServiceAccounts need no annotations. EKS keys the association by namespace and ServiceAccount name, so leave the eks.amazonaws.com/role-arn annotations out of your Helm values.

Values to record​

The IAM-auth values omit any password Secret. hub-core reads the auth mode and cloud from environment variables emitted by the chart. It then builds an RDS auth token from the Pod's IAM credentials. It uses that token as the PostgreSQL password on every new pool connection. The migration Job receives the same settings and authenticates the same way. TLS is required: in IAM mode the chart upgrades an unset or disable postgresql.sslmode to require.

Record these values and enter them in the AWS IAM authentication tab in step 4 of the install guide:

ValueWhere it came from
RDS endpoint hostnameThe provisioned instance
AWS regionThe provisioned instance
Database name and userhub and hub, from the SQL above
IAM role ARNThe role you attached the policy to. IRSA only

The completed block should look like this:

hub-core:
api:
serviceAccount:
create: true
# Only needed for IRSA. Pod Identity does not use ServiceAccount annotations.
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/hub-core
migration:
serviceAccount:
# Only needed for IRSA. The migration Job runs as hub-core-migrate.
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/hub-core

postgresql:
host: <rds-endpoint>
port: 5432
database: hub
user: hub
sslmode: require

auth:
mode: iam
cloud: aws
aws:
region: <region>
note

The chart ignores its postgresql.connectionString value when auth.mode=iam. Use the discrete host, port, database, and user fields.

Troubleshoot IAM auth​

Once you've installed Hub, watch the hub-core Pods roll out:

kubectl -n hub rollout status deployment/hub-core

A migration Job (hub-core-migrate-<hash>, running as ServiceAccount hub-core-migrate) applies the schema. Each hub-core Pod's init-migrate init container waits until the schema is current before the API server starts. All of them use the same IAM auth path, so a successful rollout means both the migration Job and the server authenticated against RDS.

If the rollout stalls, check the migration Job first:

kubectl -n hub get jobs
kubectl -n hub logs job/<hub-core-migrate-job-name>

Look in the Job or Pod logs for one of these:

  • database auth aws region is required. postgresql.auth.aws.region is empty and the Pod has no AWS_REGION environment variable. Set the value in values.yaml.

  • PAM authentication failed (in the RDS log). The IAM role is missing rds-db:connect for the resource, the DbiResourceId in the policy is wrong, the role doesn't trust the ServiceAccount that's connecting (hub-core or hub-core-migrate), or the database role wasn't granted rds_iam.

  • hstore must live in the extensions schema. The extension was created outside the extensions schema, and hub can't move it. Have the master user move it, let hub use the schema, and add the schema to the database's search path:

    \c hub
    CREATE SCHEMA IF NOT EXISTS extensions;
    GRANT USAGE ON SCHEMA extensions TO hub;
    ALTER EXTENSION hstore SET SCHEMA extensions;
    ALTER DATABASE hub SET search_path TO "$user", public, extensions;

    Then run the migration Job again.

Log in to Hub and confirm at least one ControlPlane has been registered or can be created. Schema is in place when the UI lists resources without errors.

Password authentication (fallback)​

Use this section only if you can't use IAM authentication, such as when running outside AWS or on a Kubernetes cluster without workload identity. Password mode stores a long-lived credential in a Secret. Rotate it through whatever secret-management tool your organization already uses.

Create the database role with a password rather than the rds_iam grant:

CREATE USER hub WITH PASSWORD '<your-password>';
GRANT ALL PRIVILEGES ON DATABASE hub TO hub;

Then use the Password authentication tab in step 4 of the install guide instead of the IAM tab, with the RDS endpoint as the host. Step 2 of that guide creates the Secret holding the password you set above. Skip the IAM role, policy, and ServiceAccount setup on this page entirely.

Everything else (TLS, security groups, schema bootstrap) works the same as the IAM path.

Next step​

Return to the self-hosted install guide to finish wiring Hub against the database you just provisioned.