AWS Database Blog

Automating Amazon RDS backup and maintenance windows for Daylight Saving Time shifts

Twice a year, some database administrators face the same tedious task: manually adjusting Amazon Relational Database Service (Amazon RDS) backup and maintenance schedules across multiple instances when Daylight Saving Time (DST) begins or ends. Because RDS operates on Coordinated Universal Time (UTC) while backup and maintenance schedules often reflect local time zones, each spring and fall, DST shifts create misalignment between intended schedules and actual execution times, which shifts maintenance windows by an hour and potentially disrupting planned activities during critical business hours. When you add the complexity of cron jobs operating on local system time while RDS maintains UTC, you face risks of missed backups, maintenance occurring during business hours, and compliance violations. By automating RDS backup and maintenance windows to adjust to time shifts, it eliminates manual DST adjustments and you’ll have consistent database operations across DST transitions while reducing operational overhead and scheduling errors.

In this post, you’ll learn how to deploy a serverless solution using AWS CloudFormation that automatically adjusts RDS maintenance and backup windows for DST transitions. You’ll configure Amazon EventBridge rules to trigger AWS Lambda functions on DST changes, set up cross-account AWS Identity and Access Management (AWS IAM) roles for managing RDS resources across multiple accounts, and implement tag-based filtering to selectively update specific instances. We’ll also cover testing the solution and monitoring execution through Amazon CloudWatch logs and Amazon Simple Notification Service (Amazon SNS) notifications.

Solution overview

An EventBridge rule triggers a Lambda function twice a year, coinciding with the switch to and from DST. The function, deployed in a designated AWS account, assumes an IAM role in the target AWS account to update RDS maintenance and backup windows. CloudFormation templates simplify deployment and management by defining the necessary resources as infrastructure as code.

The following image shows the architecture and process:

Architecture diagram showing an automated cross-account Amazon RDS backup and maintenance workflow using Amazon EventBridge, AWS Lambda, AWS STS, Amazon CloudWatch, Amazon SNS, and Amazon RDS across a Designated AWS Account and a Target AWS Account

  1. EventBridge triggers the Lambda function on DST transitions
  2. Lambda retrieves IAM role ARNs from SSM Parameter Store
  3. Lambda assumes cross-account role via AWS STS for target account access
  4. Lambda updates RDS windows by adjusting maintenance and backup times
  5. Lambda receives RDS confirmation that updates completed successfully
  6. Lambda logs all operations to CloudWatch for monitoring and troubleshooting
  7. Lambda sends status notification to SNS

Prerequisites

Before deploying this solution, you need:

  • An AWS account to deploy CloudFormation stacks and Lambda functions
  • IAM permissions to create CloudFormation stacks, Lambda functions, IAM roles, EventBridge rules, and SNS topics
  • An Amazon RDS cluster or instance that will have their maintenance and backup windows adjusted
  • AWS Command Line Interface (AWS CLI) installed and configured to execute deployment commands and interact with AWS services from your local environment
  • An Amazon Simple Storage Service (Amazon S3) bucket to store the Lambda deployment package before CloudFormation can reference it

With these prerequisites in place, you’re ready to deploy the solution. The deployment follows a three-phase approach that establishes secure cross-account access and automation.

Deploy the solution

The deployment process consists of three main phases that work together to create a secure, cross-account automation solution. Each phase builds upon the previous one to establish the complete infrastructure.

Overview of deployment phases

Phase 1: Deploy core functionality in the designated AWS account

Create the automation engine that manages your RDS resources by deploying:

  • EventBridge rules – Automatically trigger the Lambda function twice a year when DST starts and ends
  • Lambda function – Contains the logic to calculate new time windows and update RDS resources
  • IAM role for Lambda – Grants permissions to assume roles in target accounts and modify RDS settings
  • AWS Systems Manager parameter – Stores the list of target account IAM role Amazon Resource Names (ARNs) that Lambda can assume
  • SNS topic – Sends notifications about successful or failed updates

Your “control plane” orchestrates DST adjustments across your organization.

Phase 2: Deploy IAM permissions in the target AWS account

Establish the trust relationship that allows the Lambda function to access RDS resources in other accounts by creating:

  • IAM role in target account – Grants specific permissions to describe and modify RDS instances and clusters
  • Trust policy – Allows the Lambda execution role from Phase 1 to assume this role

A secure, least-privilege access pattern enables cross-account operations. If your RDS resources are in the same account as the Lambda function, you can deploy both stacks in the same account.

Phase 3: Update the IAM role in the designated AWS account

The final phase connects everything together by updating the Lambda function’s configuration with the actual IAM role ARNs from Phase 2. This replaces the wildcard placeholder (*) with specific role ARNs, following the principle of least privilege.

Now let’s walk through each deployment phase with detailed CLI commands.

Step 1: Clone the GitHub repository

Obtain the CloudFormation templates and Lambda function code from the GitHub repository:

# Clone the repository
git clone https://github.com/aws-samples/sample-rds-dst-automation.git

# Navigate to the project directory
cd sample-rds-dst-automation

You’ll now have access to:

  • templates/DSTMaster.yaml – CloudFormation template for Phase 1.
  • templates/DSTAccount.yaml – CloudFormation template for Phase 2.
  • src/rds.py – Lambda function code that performs the time adjustments.

Step 2: Deploy core functionality in the designated AWS account

Deploy the automation engine that manages your RDS resources across multiple accounts.

Create Lambda Package

Package the Lambda function code and upload it to S3:

# Create deployment directory
mkdir -p deployment

# Create Lambda package
cd src
zip -r ../deployment/rds-function.zip rds.py
cd ..

# Upload to S3 (replace <S3-BUCKET> with your bucket name)
aws s3 cp deployment/rds-function.zip s3://<S3-BUCKET>/

# Clean up (optional)
rm -rf deployment

Deploy Master Stack

Deploy the CloudFormation stack that creates the core resources:

aws cloudformation create-stack \
  --stack-name RDSDSTMasterStack \
  --template-body file://templates/DSTMaster.yaml \
  --parameters \
    ParameterKey=LambdaS3Bucket,ParameterValue=<S3-BUCKET> \
    ParameterKey=AlertEmail,ParameterValue=<EMAIL> \
    ParameterKey=Regions,ParameterValue=us-east-1\\,us-east-2 \
    ParameterKey=Tags,ParameterValue=Environment=none\
    ParameterKey=DSTStartScheduleExpression,ParameterValue="0 8 ? MAR 1#2 *" \
    ParameterKey=DSTEndScheduleExpression,ParameterValue="0 8 ? NOV 1#1 *" \
    ParameterKey=DSTAccountRoleArns,ParameterValue="*" \
  --capabilities CAPABILITY_NAMED_IAM

Replace the following parameters:

  • <S3-BUCKET> – S3 bucket containing your Lambda deployment package
  • <EMAIL> – Email address that will receive SNS notifications about DST updates
  • Adjust Regions with comma-separated AWS regions where you have RDS resources
  • Update Tags with comma-separated tags in key=value format to filter resources, or use “none” to update every resource (Ex. env=prod\\,dept=finance)
  • Customize DSTStartScheduleExpression and DSTEndScheduleExpression for your region (see DST Schedules)

Note: Set DSTAccountRoleArns to “*” initially. We will update this with actual role ARNs in Step 4.

Wait for stack creation and retrieve outputs

# Wait for stack creation to complete (takes approximately 2 minutes)
aws cloudformation wait stack-create-complete --stack-name RDSDSTMasterStack

# Get the Lambda IAM Role ARN (save this for the next step)
aws cloudformation describe-stacks \
  --stack-name RDSDSTMasterStack \
  --query 'Stacks[0].Outputs[?OutputKey==`LambdaExecutionRoleArn`].OutputValue' \
  --output text

Save the Lambda IAM Role ARN for the next step to establish the trust relationship.

Step 3: Deploy IAM permissions in the target AWS account

Create the IAM role that allows the Lambda function to access and modify RDS resources in the target account.

Deploy Account Stack

Deploy the account stack with the Lambda IAM Role ARN from Step 2:

aws cloudformation create-stack \
  --stack-name RDSDSTAccountStack \
  --template-body file://templates/DSTAccount.yaml \
  --parameters ParameterKey=DSTMasterLambdaRoleArn,ParameterValue=<LAMBDA_ROLE_ARN> \
  --capabilities CAPABILITY_NAMED_IAM

Replace <LAMBDA_ROLE_ARN> with the Lambda IAM Role ARN from Step 2.

Wait for the stack to complete and retrieve the account IAM Role ARN:

# Wait for stack creation to complete
aws cloudformation wait stack-create-complete --stack-name RDSDSTAccountStack

# Get the Account IAM Role ARN (save this for the next step)
aws cloudformation describe-stacks \
  --stack-name RDSDSTAccountStack \
  --query 'Stacks[0].Outputs[?OutputKey==`DSTAccountRoleArn`].OutputValue' \
  --output text

Note: For multiple target accounts, repeat this step in each AWS account that hosts RDS resources you want to manage. Save all the Account IAM Role ARNs for the next step.

Step 4: Update the IAM role in the designated AWS account

Connect the Lambda function to the target account roles, completing the cross-account access configuration.

Update Master Stack with Account Role ARNs

Update the master stack with the Account IAM Role ARN from Step 3:

aws cloudformation update-stack \
  --stack-name RDSDSTMasterStack \
  --use-previous-template \
  --parameters \
    ParameterKey=LambdaS3Bucket,UsePreviousValue=true \
    ParameterKey=AlertEmail,UsePreviousValue=true \
    ParameterKey=Regions,UsePreviousValue=true \
    ParameterKey=Tags,UsePreviousValue=true \
    ParameterKey=DSTStartScheduleExpression,UsePreviousValue=true \
    ParameterKey=DSTEndScheduleExpression,UsePreviousValue=true \
    ParameterKey=DSTAccountRoleArns,ParameterValue=<ACCOUNT_ROLE_ARN> \
  --capabilities CAPABILITY_NAMED_IAM

Replace <ACCOUNT_ROLE_ARN> with the Account IAM Role ARN from Step 3.

For multiple accounts, provide all role ARNs as a comma-separated list:

ParameterKey=DSTAccountRoleArns,ParameterValue=arn:aws:iam::111111111111:role/Role1\\,arn:aws:iam::222222222222:role/Role2

Important: When adding new role ARNs later, you must include the existing ARNs plus the new ones. CloudFormation replaces the entire parameter value rather than appending to it.

Wait for stack update to complete

Wait for the update to finish:

aws cloudformation wait stack-update-complete --stack-name RDSDSTMasterStack

The solution is now fully deployed and ready to automatically adjust RDS maintenance and backup windows during DST transitions.

Test the solution

Now that you’ve deployed the solution, verify that it works correctly before relying on it for production workloads. Testing in a non-production environment allows you to confirm that the Lambda function can successfully access your RDS resources, verify that maintenance and backup windows are adjusted correctly, understand the notification flow and log output, validate cross-account access if you’re using multiple AWS accounts, and confirm that tag-based filtering works as expected.

While the EventBridge rules will automatically trigger the Lambda function during actual DST transitions, you can manually invoke the function to test the behavior at any time.

Test DST Start (Spring Forward)

Invoke the Lambda function to simulate DST start, which shifts maintenance and backup windows 1 hour earlier:

aws lambda invoke \
  --function-name RDSDSTMasterStack-function \
  --payload '{"dst": "true"}' \
  --cli-binary-format raw-in-base64-out \
  response.json

# View the response
cat response.json

Expected response:

{"statusCode": 200, "message": "Successfully Started DST"}

Test DST End (Fall Back)

Invoke the Lambda function to simulate DST end, which shifts maintenance and backup windows 1 hour later:

aws lambda invoke \
  --function-name RDSDSTMasterStack-function \
  --payload '{"dst": "false"}' \
  --cli-binary-format raw-in-base64-out \
  response.json

# View the response
cat response.json

Expected response:

{"statusCode": 200, "message": "Successfully Ended DST"}

Verify the changes

After invoking the Lambda function, verify that the RDS maintenance and backup windows have been updated:

Check RDS instance windows:

aws rds describe-db-instances \
  --db-instance-identifier <INSTANCE-ID> \
  --query 'DBInstances[0].[PreferredMaintenanceWindow,PreferredBackupWindow]'

Check RDS cluster windows:

aws rds describe-db-clusters \
  --db-cluster-identifier <CLUSTER-ID> \
  --query 'DBClusters[0].[PreferredMaintenanceWindow,PreferredBackupWindow]'

Verify DST tag

aws rds list-tags-for-resource \
  --resource-name <INSTANCE-ARN> \
  --query 'TagList[?Key==`dst`]'

The DST tag value should match your test (“true” for DST start or “false” for DST end).

View Lambda execution logs:

aws logs tail /aws/lambda/RDSDSTMasterStack-function --since 10m --format short

Or view the most recent log stream:

aws logs describe-log-streams \
  --log-group-name "/aws/lambda/RDSDSTMasterStack-function" \
  --order-by LastEventTime --descending --max-items 1

Expected results

The following examples show how maintenance and backup windows are adjusted. Your actual windows will vary based on your RDS configuration.

When DST starts (spring forward), maintenance and backup windows shift 1 hour earlier:

  • Original: sun:02:00-sun:03:00 → Updated: sun:01:00-sun:02:00
  • Original: 03:00-04:00 → Updated: 02:00-03:00

When DST ends (fall back), maintenance and backup windows shift 1 hour later:

  • Original: sun:02:00-sun:03:00 → Updated: sun:03:00-sun:04:00
  • Original: 03:00-04:00 → Updated: 04:00-05:00

Clean up

After testing the solution or if you decide this automation no longer meets your needs, you can remove the deployed resources to avoid ongoing charges.

To delete the other resources that were launched as part of the CloudFormation stacks, complete the following steps in both the designated account and the target account.

Delete the stacks

In the designated account:

# Delete the master stack
aws cloudformation delete-stack --stack-name RDSDSTMasterStack

# Wait for deletion to complete (optional)
aws cloudformation wait stack-delete-complete --stack-name RDSDSTMasterStack

In the target account(s):

# Delete the account stack
aws cloudformation delete-stack --stack-name RDSDSTAccountStack

# Wait for deletion to complete (optional)
aws cloudformation wait stack-delete-complete --stack-name RDSDSTAccountStack

Note: Repeat the account stack deletion for each target account where you deployed the RDSDSTAccountStack.

Conclusion

In this post, we presented an automated solution that helps you maintain consistent RDS backup and maintenance windows throughout the year, regardless of DST changes. The approach removes the manual effort of adjusting these windows twice a year, reduces the risk of human error, and keeps your database operations running as expected.

The solution is particularly useful if your organization operates across multiple time zones, have strict maintenance window requirements, need to maintain consistent scheduling relative to business hours, or want to reduce operational overhead and eliminate manual processes.

To learn more about the implementation of this automated solution, you can visit this aws-samples github page.


About the authors

Naseer Sayyad

Naseer Sayyad

Naseer is an AWS professional supporting enterprise-level customers, providing strategic guidance on cloud resiliency, security best practices, and generative AI adoption, helping organizations architect scalable, secure, and innovative solutions that accelerate digital transformation. Outside of work, he enjoys photography, playing tennis, and going on drives with his family.

Prashant Chaudhari

Prashant Chaudhari

Prashant is an AWS Solution Architect who acts as a strategic technical advisor, guiding enterprise clients through the intricacies of cloud-native design. He excels at translating complex business needs into resilient, scalable infrastructure by utilizing the expansive AWS ecosystem. His approach focuses on driving innovation and operational excellence, ensuring all architectural choices align with the Well-Architected Framework.

Paras Babbar

Paras Babbar

Paras is as an Enterprise Support lead at AWS. He works alongside enterprise customers as a trusted cloud advisor, helping them cut through complexity and turn ambitious goals into tangible results. When he’s not in the cloud, you’ll find him on the cricket field or on the pickleball court rallying it out with his wife.