Skip to main content

Automatically Sync IP Targets for Amazon RDS and Aurora Endpoints

Amazon RDS and Amazon Aurora endpoints are DNS names. AWS can change the private IP addresses behind these endpoints during events such as failover, maintenance, or scaling. Because the target group uses IP targets, VeloDB Cloud recommends using AWS Lambda to keep the target group synchronized with the current endpoint resolution.

This guide assumes that you have already configured the target group and Network Load Balancer described in Grant VeloDB Access to Your VPC on AWS.

Automation workflow

1. Prepare the target group and DNS resolution

  1. In the AWS EC2 console, open Target Groups and record the target group ARN and the port configured for its targets.

  2. Confirm that the target group uses IP addresses with an IPv4 address type and that the NLB subnets can route to the database.

  3. Confirm that the Lambda runtime will use a VPC, subnet, and security group that can resolve the RDS or Aurora endpoint through private DNS. See Configuring Lambda functions to access resources in a VPC.

  4. From an instance or other host in that network, verify the endpoint resolves to private addresses:

    dig +short <your-rds-endpoint>

For endpoint behavior, see Amazon RDS instance endpoints and Amazon Aurora connection management.

2. Create the Lambda function

  1. Open the AWS Lambda console and click Create function.
  2. Choose Author from scratch, select a supported Python runtime, and configure the execution role. The role must include permissions to write logs, manage the Lambda VPC network interfaces, and call the Elastic Load Balancing API actions listed in Lambda permissions.
  3. If the function runs in a VPC, select the VPC, private subnets, and a security group that allow DNS queries and access to the database endpoint. Ensure the function has a route to AWS APIs through a NAT gateway or the required VPC endpoints.
  4. Paste the example from Lambda example, or deploy the equivalent code through your normal packaging pipeline.

3. Configure and test the function

  1. In the function's Configuration > Environment variables section, add:

    VariableValue
    DB_ENDPOINTThe RDS or Aurora endpoint DNS name.
    TARGET_GROUP_ARNThe target group ARN from step 1.
    TARGET_PORTThe database port, such as 3306 or 5432.
  2. In the Test tab, create a test event with {} as the event JSON and invoke the function.

  3. Review the response and the function's CloudWatch Logs to confirm that resolved_ips, added, and removed match the expected target changes.

  4. In the AWS EC2 Target Groups console, verify the registered targets and their health.

The function should be idempotent: when DNS results already match the target group, a run should make no changes.

4. Schedule recurring synchronization

  1. Open the Amazon EventBridge console and create a rule with a recurring schedule, such as every 1 to 5 minutes.
  2. Select the Lambda function as the target and grant EventBridge permission to invoke it when prompted. See Creating an Amazon EventBridge rule that runs on a schedule.
  3. Enable the rule and invoke it once manually to confirm that the schedule reaches the function.
  4. If your operations process captures RDS or Aurora events, you can also route failover or maintenance events through EventBridge. See Monitoring Amazon RDS events with Amazon EventBridge.

5. Verify failover handling

  1. Confirm that the Lambda function runs successfully on its schedule and that CloudWatch logs are retained for operational review.
  2. During a planned maintenance or failover test, observe the endpoint resolution and target-group membership.
  3. Confirm that new private IP addresses are registered, stale addresses are deregistered, and the NLB target remains healthy before using the connection in production.

Lambda permissions

The Lambda execution role needs permissions to describe, register, and deregister target group targets, for example:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets"
],
"Resource": "<your-target-group-arn>"
}
]
}

Lambda example

The following Python example resolves the database endpoint and keeps one target group in sync. Configure the Lambda function with the environment variables DB_ENDPOINT, TARGET_GROUP_ARN, and TARGET_PORT.

import os
import socket

import boto3


elbv2 = boto3.client("elbv2")


def resolve_endpoint(endpoint):
return {
result[4][0]
for result in socket.getaddrinfo(endpoint, None, family=socket.AF_INET)
}


def list_registered_targets(target_group_arn):
response = elbv2.describe_target_health(TargetGroupArn=target_group_arn)
return {
target["Target"]["Id"]
for target in response["TargetHealthDescriptions"]
}


def lambda_handler(event, context):
endpoint = os.environ["DB_ENDPOINT"]
target_group_arn = os.environ["TARGET_GROUP_ARN"]
target_port = int(os.environ["TARGET_PORT"])

resolved_ips = resolve_endpoint(endpoint)
registered_ips = list_registered_targets(target_group_arn)

targets_to_add = resolved_ips - registered_ips
targets_to_remove = registered_ips - resolved_ips

if targets_to_add:
elbv2.register_targets(
TargetGroupArn=target_group_arn,
Targets=[
{"Id": ip, "Port": target_port}
for ip in sorted(targets_to_add)
],
)

if targets_to_remove:
elbv2.deregister_targets(
TargetGroupArn=target_group_arn,
Targets=[
{"Id": ip, "Port": target_port}
for ip in sorted(targets_to_remove)
],
)

return {
"endpoint": endpoint,
"resolved_ips": sorted(resolved_ips),
"registered_before": sorted(registered_ips),
"added": sorted(targets_to_add),
"removed": sorted(targets_to_remove),
}

Keep the Lambda function lightweight and idempotent. If the resolved IP addresses already match the target group, the function should make no changes. Before using the PrivateLink connection in production, verify that the automation can register new targets and remove stale targets without interrupting database access.