Connecting to a Private or Shield Heroku Postgres Database via PrivateLink
Last updated May 30, 2023
Table of Contents
This article describes how to use AWS PrivateLink to create a secure connection between an AWS VPC and a Heroku Postgres database running in a Private Space or a Shield Private Space. This process involves three high-level steps:
- Creating an Endpoint Service on your Heroku Postgres database
- Creating an Endpoint Network Interface in your AWS VPC
- Establishing the secure connection between the two endpoints
As part of setting up the connection, you can specify a list of approved accounts to limit access to your Heroku Postgres database from the VPC.
To use this feature, the Amazon VPC Endpoint you create must be provisioned in a subnet that is in the same region as your Heroku Postgres database.
Heroku Prerequisites
The following Heroku resources are required to set up a PrivateLink endpoint:
A Private Space. This article describes how to create a Private Space using either the Heroku Dashboard or the Heroku CLI.
A Shield Private Space. This article describes how to create a Shield Private Space using either the Heroku Dashboard or the Heroku CLI.
A Heroku app running in the Private Space or Shield Private Space with an attached Heroku Postgres database. All Heroku Postgres instances running in a Private Space or a Shield Private Space use one of the
private
orshield
plan types, respectively.
Provisioning the Heroku endpoint
Step 1: Install the Heroku Data via PrivateLink CLI Plugin
$ heroku plugins:install @heroku-cli/plugin-data-privatelink
Step 2: Obtain Your AWS Account ID
You can obtain your AWS account ID with the AWS CLI like so:
$ aws sts get-caller-identity --output text --query 'Account'
123456789101
The example command returns an account ID of 123456789101
.
You can also obtain your account ID from the My Account page of your AWS account. The Account ID is shown in the Account Settings section:
Step 3: Create a PrivateLink endpoint
Create a PrivateLink endpoint using the following Heroku CLI command (note the values to substitute):
$ heroku data:privatelink:create POSTGRESQL_ADDON_NAME --aws-account-id ACCOUNT_ID --app APP_NAME
- Replace
POSTGRESQL_ADDON_NAME
with the name of your Heroku Postgres database (for example,postgresql-sushi-12345
). - Replace
APP_NAME
with your app’s name. - Replace
ACCOUNT_ID
with the AWS account that receives access to your Heroku Postgres database. This ID can match any of the following patterns:- account-id
- account-id:user/username
- account-id:role/rolename
You can specify the --aws-account-id
flag multiple times to include multiple accounts.
Here’s an example command with accompanying output:
$ heroku data:privatelink:create postgresql-sushi-12345 --aws-account-id 123456789101:user/abc.xyz --app privatelink-vpc-endpoint-demo
Creating privatelink... done
Service Name: Provisioning
Status: Provisioning
The privatelink is now being provisioned for postgresql-sushi-12345.
Run heroku data:privatelink:wait postgresql-sushi-12345 -a APP to check the creation process.
New PrivateLink endpoints typically take 5–10 minutes to become available. You can track your progress with heroku data:privatelink:wait postgresql-sushi-12345 --app APP_NAME
.
Step 4: Obtain Your Endpoint’s Service Name
When the PrivateLink endpoint finishes provisioning, use the following command to view its details:
$ heroku data:privatelink POSTGRESQL_ADDON_NAME --app APP_NAME
Replace POSTGRESQL_ADDON_NAME
with the name of your Heroku Postgres database, and replace APP_NAME
with your app’s name.
Here’s an example command with accompanying output:
$ heroku data:privatelink postgresql-sushi-12345 --app privatelink-vpc-endpoint-demo
=== privatelinks for postgresql-sushi-12345
Service Name: com.amazonaws.vpce.us-east-1.vpce-svc-0410a2e25933fe8ec
Status: Operational
=== Allowed Accounts
ARN Status
arn:aws:iam::123456789101:user/abc.xyz Active
Your privatelink is now operational.
You must now copy the Service Name and follow the rest of the steps listed in https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink.
Copy the value of the Service Name
field from the command’s output (in the example above, the value is com.amazonaws.vpce.us-east-1.vpce-svc-0410a2e25933fe8ec
). You need this value to provision the Amazon VPC endpoint.
Provisioning the Amazon VPC Endpoint
You perform the steps in this section from your Amazon VPC dashboard.
Step 1: Create and Configure a Security Group
Your endpoint requires a security group with appropriate ingress security rules. Click Create security group
in the Security Groups
tab of your VPC dashboard:
Specify an appropriate security group name and description and select your desired VPC before clicking Create
:
Select your newly created security group from the list and click Actions > Edit inbound rules
:
Enable TCP access to ports 5432–5433
from any valid IP address and click Save rules
:
Step 2: Create the endpoint
Navigate to the Endpoints
tab of your VPC dashboard and click Create Endpoint
:
In the Create Endpoint form that appears, select the Find service by name option and paste the Service Name
value you obtained earlier.
Then click Verify
to display the list of available subnets:
Attach the security group you created earlier to the VPC Endpoint and click Create endpoint
:
The endpoint is created with an initial status of pending acceptance
, which transitions to available
after 5-10 minutes:
Connecting the Heroku and Amazon VPC Endpoints
After the Amazon VPC endpoint becomes available
, you can obtain the URLs from the config vars that Heroku creates to allow your VPC to communicate with your Heroku Postgres database (DATABASE_ENDPOINT_ID_URL
) and PgBouncer (DATABASE_ENDPOINT_ID_PGBOUNCER_URL
).
PgBouncer is a service that lets you set up connection pooling for Heroku Postgres databases. Learn more about connection pooling with Heroku Postgres.
First, obtain your PrivateLink endpoint’s Endpoint ID and extract the 17-character string that appears at the end of it. Convert that string to upper case and use it in the following command.
For example, if the Endpoint ID is vpce-01c87ae3c05563935
, the Endpoint ID is 01C87AE3C05563935
.
Run the following command, substituting the obtained string where indicated:
$ heroku config --app your_app_name | grep ENDPOINT_ID_HERE
This command displays the AWS VPC Endpoint connection URL and the corresponding connection string for your Heroku Postgres database. The connection string has the following format:
postgres://user:password@vpc-endpoint-dns-name:5432/database
You can now use this connection string to connect the applications in your AWS VPC to your private Heroku Postgres database and PgBouncer instance. Here’s an example command with accompanying output:
$ heroku config --app privatelink-vpc-endpoint-demo | grep 01C87AE3C05563935
DATABASE_ENDPOINT_01C87AE3C05563935_URL: postgres://abcdefghijklmn:abcdefghijklmnopqrstuvwxyz123456789101112131415161718192021222324@ec2-3-83-63-168.compute-1.amazonaws.com:5432/dd0k757ojc5qt
DATABASE_ENDPOINT_01C87AE3C05563935_PGBOUNCER_URL: postgres://abcdefghijklmn:abcdefghijklmnopqrstuvwxyz123456789101112131415161718192021222324@ec2-3-83-63-168.compute-1.amazonaws.com:5433/dd0k757ojc5qt
For any issues or concerns with using this feature, open a support ticket.
Connecting to Heroku Postgres from EC2 via VPC Endpoints
After you configure your VPC endpoints, you can create an EC2 instance in your AWS VPC to connect to Heroku Postgres.
Click Launch Instance
in your EC2 dashboard and select your AMI and Instance Type. In this example, an Ubuntu t2.micro instance is created:
When configuring the instance’s details, select the VPC network with the security group you created earlier and pick an appropriate subnet. Click Review and Launch
and launch the EC2 instance.
After the instance’s status transitions to running
and all status checks have passed, connect to the instance using the SSH key pair you specified during instance creation.
After it’s connected, install Postgres on your EC2 instance with the following commands:
$ sudo apt-get -qq update && sudo apt-get install -y curl ca-certificates
$ curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
$ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
$ sudo apt-get -qq update
$ sudo apt-get install -y postgresql-client-10
You can then connect to your Heroku Postgres database from the EC2 instance using the following command:
$ psql postgres://user:password@vpc-endpoint-dns-name:5432/database
The following screenshot shows the connection string being used to connect to a Heroku Postgres database from within a sample EC2 instance:
Limitations
- The Amazon VPC Endpoint you create must be provisioned in a subnet that is in the same region as your Heroku Postgres database.
- It is your responsibility to verify the security of your VPC to ensure fully secure access to your Heroku Postgres database.
Comparison to Private Space Trusted IP Ranges
Private Spaces support trusted IP ranges for data services as a beta feature. This feature is an option if you must connect to a Heroku Postgres database from outside the Private Space boundary. However, you must contact Heroku to enable this feature, and granular access control isn’t available for it.
By connecting via AWS PrivateLink, your database is treated as part of your own VPC, and you can restrict access to a set of users and roles. Consequently, this method is recommended whenever it’s available for your use case.