Connecting through AWS PrivateLink via NLB

Paid add-on

Connecting to your database with AWS PrivateLink is a paid add-on. Contact [email protected] to enable.

This guide walks through exposing an existing Amazon RDS PostgreSQL instance to Polytomic over AWS PrivateLink using a Network Load Balancer and a VPC Endpoint Service. This is the classic, well-trodden PrivateLink pattern.

If your RDS instance is Multi-AZ and you need automatic failover tolerance without manual intervention, see
Connecting PostgreSQL through AWS PrivateLink (VPC Lattice) instead. The NLB path pins a specific RDS IP and requires re-running Terraform on failover.

How it works

Although the specific technical steps are listed in subsequent sections below, here is the general outline you'll follow to set this up:

  1. Create an internal Network Load Balancer in the same VPC as your RDS instance, with an IP target group pointing at the RDS instance's current IP.
  2. Create a VPC Endpoint Service fronted by that NLB and add Polytomic's AWS account to its allowed_principals.
  3. Send Polytomic the endpoint service name.
  4. Polytomic will create an Interface VPC Endpoint in its own VPC against your service name. Connections will originate from Polytomic, transit the PrivateLink fabric, hit your NLB, and terminate at RDS.

At no point does traffic traverse the public internet. No IAM roles, bastions, or VPC peering are required on either side.

Prerequisites

Before you start, collect:

  • The VPC ID containing your RDS instance.
  • At least two private subnet IDs in distinct Availability Zones. The NLB will live in these subnets.
  • The RDS instance's hostname, port, and security group ID.
  • Polytomic's AWS account ID — ask your Polytomic Solutions Engineer if you don't already have it.

Option 1: Terraform (recommended)

Polytomic publishes a module that creates the NLB, target group, listener, endpoint service, and security group rule in one shot.

provider "aws" {
  region = "us-east-1"
}

module "polytomic_privatelink" {
  source = "github.com/polytomic/on-premises/terraform/modules/aws-privatelink-rds-nlb"

  name       = "polytomic"
  vpc_id     = "vpc-0123456789abcdef0"
  subnet_ids = [
    "subnet-aaaa",  # private subnet in us-east-1a
    "subnet-bbbb",  # private subnet in us-east-1b
    "subnet-cccc",  # private subnet in us-east-1c
  ]

  rds_host              = "mydb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com"
  rds_port              = 5432
  rds_security_group_id = "sg-0123456789abcdef0"

  polytomic_aws_account_id = "123456789012"  # provided by your SE
}

output "service_name" {
  value = module.polytomic_privatelink.service_name
}

Run:

terraform init
terraform apply

Send the value of the service_name output to your Polytomic Solutions Engineer. It will look like
com.amazonaws.vpce.us-east-1.vpce-svc-0123456789abcdef0.

Option 2: AWS Console

If you'd rather not use Terraform, the same flow can be completed manually in the AWS Console.

1. Resolve the RDS IP

NLB target groups only accept IP addresses, not DNS names. From a host inside your VPC, resolve the RDS endpoint:

dig +short mydb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com
# 10.0.12.34

Note this IP — you'll register it as the NLB target.

2. Create the target group

  1. Open the EC2 console → Target Groups → Create target group.
  2. Target type: IP addresses.
  3. Protocol: TCP, Port: 5432.
  4. VPC: select the VPC containing your RDS instance.
  5. Health check: TCP on port 5432.
  6. Click Next, register the RDS IP you resolved above as a target on
    port 5432, and create the group.

3. Create the Network Load Balancer

  1. Load Balancers → Create load balancer → Network Load Balancer.
  2. Scheme: Internal.
  3. VPC: the RDS VPC. Mappings: select at least two private subnets in
    distinct AZs.
  4. Listener: TCP:5432, forwarding to the target group from step 2.
  5. Create. Wait for the NLB to reach the active state.

4. Update the RDS security group

The NLB's IP targets appear as sources from within your VPC. Add an inbound rule to the RDS security group:

  • Type: PostgreSQL
  • Protocol: TCP
  • Port: 5432
  • Source: the VPC CIDR (e.g. 10.0.0.0/16)

5. Create the VPC Endpoint Service

  1. VPC → Endpoint services → Create endpoint service.
  2. Load balancer type: Network. Select the NLB from step 3.
  3. Acceptance required: No (the allowlist below handles authorization).
  4. Create. Note the service name (com.amazonaws.vpce.<region>.vpce-svc-…).
  5. Open the service → Allow principals → add Polytomic's account:
    arn:aws:iam::<POLYTOMIC_ACCOUNT_ID>:root.

6. Send the service name to Polytomic

Email your Solutions Engineer the service name from step 5.

Troubleshooting

terraform apply succeeds but Polytomic can't connect.

Check that the inbound rule on the RDS security group actually allows the VPC CIDR on 5432. The Terraform module adds it automatically; if you went the console route, double-check step 4.

Connection worked, then started timing out after a few hours/days.

RDS probably failed over to a different IP. Re-run terraform apply — the target group will pick up the new IP and re-register. If this happens frequently, switch to the VPC Lattice variant, which handles failover automatically.

NLB target shows as unhealthy.

The target group health check is TCP on 5432. Verify the RDS security group allows the NLB traffic, and that you registered the correct IP (compare against a fresh dig of the RDS endpoint).

"Principal cannot be added to this endpoint service."

The account ID you received from Polytomic may be wrong. Confirm it with your Solutions Engineer before retrying.