Connecting through AWS PrivateLink via NLB

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

  1. You 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. You create a VPC Endpoint Service fronted by that NLB, and add Polytomic's AWS account to its allowed_principals.
  3. You send Polytomic the endpoint service name.
  4. Polytomic creates an Interface VPC Endpoint in its own VPC against your service name. Connections originate from Polytomic, transit the PrivateLink fabric, hit your NLB, and terminate at RDS.

At no point does traffic traverse the public internet, and 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 GroupsCreate 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 BalancersCreate load balancerNetwork 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. VPCEndpoint servicesCreate 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.