An AWS Lambda function written in Go that automatically stops RDS database instances. Designed to counter AWS's behavior of automatically restarting stopped RDS instances after 7 days.
AWS automatically restarts any stopped RDS instance after 7 days. For databases that are rarely used (e.g., once every two months), this results in unnecessary running costs. This Lambda function listens for the RDS restart event and immediately stops the instance again.
RDS auto-restarts after 7 days
-> RDS emits event RDS-EVENT-0088 ("DB instance has been started")
-> Amazon EventBridge matches the event pattern
-> Invokes this Lambda function
-> Lambda checks instance status via DescribeDBInstances
-> If status is "available", calls StopDBInstance
-> Instance stops again automatically
- Runtime: Go (compiled to static binary)
- Lambda Runtime:
provided.al2023(Amazon Linux 2023) - Architecture: ARM64 (AWS Graviton2 - lower cost)
- AWS SDK: aws-sdk-go-v2
- Trigger: Amazon EventBridge rule on RDS instance state change
By default, the function targets the instance defined in main.go. You can override this via the TARGET_INSTANCES environment variable (comma-separated for multiple instances):
TARGET_INSTANCES=my-db-1,my-db-2,my-db-3
Before deploying, update the default instance identifier in main.go:
return []string{"your-rds-instance-identifier"}- Go 1.23 or later
- AWS CLI configured (for deployment)
- An AWS account with permissions to create Lambda functions, IAM roles, and EventBridge rules
makeandziputilities
The Lambda function needs an execution role with permissions to stop RDS instances and write CloudWatch logs.
Save as trust-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}Save as permissions-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:StopDBInstance"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}Permission details:
| Permission | Purpose |
|---|---|
rds:DescribeDBInstances |
Check the current status of the RDS instance |
rds:StopDBInstance |
Send the stop command to the RDS instance |
logs:CreateLogGroup |
Create CloudWatch log group for the function |
logs:CreateLogStream |
Create log streams within the log group |
logs:PutLogEvents |
Write log entries to CloudWatch |
- Go to IAM -> Roles -> Create role
- Trusted entity type: AWS service
- Use case: Lambda
- Click Next
- Click Create policy -> JSON tab -> paste the permissions policy above
- Name it (e.g.,
LambdaRDSStopPolicy) -> Create policy - Back in the role creation, search and select the policy you just created
- Name the role (e.g.,
LambdaRDSStopRole) -> Create role - Note the role ARN (e.g.,
arn:aws:iam::<ACCOUNT_ID>:role/LambdaRDSStopRole)
# Create the role
aws iam create-role \
--role-name LambdaRDSStopRole \
--assume-role-policy-document file://trust-policy.json
# Create the policy
aws iam create-policy \
--policy-name LambdaRDSStopPolicy \
--policy-document file://permissions-policy.json
# Attach the policy to the role (replace <ACCOUNT_ID>)
aws iam attach-role-policy \
--role-name LambdaRDSStopRole \
--policy-arn arn:aws:iam::<ACCOUNT_ID>:policy/LambdaRDSStopPolicy# Clone the repository
git clone <repository-url>
cd go-lambda
# Update the target RDS instance identifier in main.go
# Edit the default in getTargetInstances() function
# Download dependencies
go mod tidy
# Build the binary and create the zip
make zipThis produces function.zip containing the bootstrap binary (~5.7MB zipped).
To verify the build:
file bootstrap
# Expected: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linkedNote: To build for x86_64 instead of ARM64, edit the
Makefileand changeGOARCH=arm64toGOARCH=amd64. You must also selectx86_64architecture when creating the Lambda function.
- Go to Lambda -> Create function
- Select Author from scratch
- Function name: choose a name (e.g.,
autostoprds-go) - Runtime:
Amazon Linux 2023(provided.al2023) - Architecture:
arm64 - Execution role: Use an existing role -> select the role from Step 1
- Click Create function
- In Code source, click Upload from -> .zip file -> upload
function.zip - Go to Runtime settings -> Edit -> set Handler to
bootstrap-> Save
aws lambda create-function \
--function-name autostoprds-go \
--runtime provided.al2023 \
--handler bootstrap \
--architectures arm64 \
--role arn:aws:iam::<ACCOUNT_ID>:role/LambdaRDSStopRole \
--zip-file fileb://function.zipaws lambda update-function-configuration \
--function-name autostoprds-go \
--environment "Variables={TARGET_INSTANCES=<your-rds-instance-id>}"The EventBridge rule listens for the RDS auto-restart event and triggers the Lambda function.
- Go to Amazon EventBridge -> Rules -> Create rule
- Name: choose a name (e.g.,
autostoprds-on-start) - Event bus:
default - Rule type: Rule with an event pattern
- Click Next
- Select Custom patterns (JSON editor) and paste:
{
"source": ["aws.rds"],
"detail-type": ["RDS DB Instance Event"],
"detail": {
"SourceIdentifier": ["<your-rds-instance-identifier>"],
"EventID": ["RDS-EVENT-0088"]
}
}- Click Next
- Target: AWS service -> Lambda function -> select your Lambda function
- Click through Next -> Create rule
Note: To monitor multiple instances, add their identifiers to the
SourceIdentifierarray:"SourceIdentifier": ["instance-1", "instance-2", "instance-3"]
# Create the rule
aws events put-rule \
--name autostoprds-on-start \
--event-pattern '{
"source": ["aws.rds"],
"detail-type": ["RDS DB Instance Event"],
"detail": {
"SourceIdentifier": ["<your-rds-instance-identifier>"],
"EventID": ["RDS-EVENT-0088"]
}
}'
# Grant EventBridge permission to invoke the Lambda
aws lambda add-permission \
--function-name autostoprds-go \
--statement-id eventbridge-invoke \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:<REGION>:<ACCOUNT_ID>:rule/autostoprds-on-start
# Add the Lambda as target
aws events put-targets \
--rule autostoprds-on-start \
--targets "Id"="1","Arn"="arn:aws:lambda:<REGION>:<ACCOUNT_ID>:function:autostoprds-go"After creating the EventBridge rule, verify it appears in the Lambda console:
- Go to Lambda -> your function -> Function overview
- EventBridge should appear as a trigger in the diagram
- If it doesn't appear, click + Add trigger -> EventBridge -> select your existing rule -> Add
-
Manual test: In the Lambda console, click Test with an empty event
{}. Check the execution result — it should show the current status of your RDS instance. -
Check CloudWatch Logs: Go to CloudWatch -> Log groups ->
/aws/lambda/<your-function-name>to see log output. -
Live monitoring: Go to CloudWatch -> Logs -> Live tail -> select your function's log group -> Start to watch logs in real-time when the event fires.
-
End-to-end test: Start your RDS instance from the console and watch the Live tail. Within a few minutes of the instance reaching
availablestatus, the Lambda should fire and stop it.
After making code changes:
make clean
make zipThen upload function.zip via the Lambda console or CLI:
aws lambda update-function-code \
--function-name <your-function-name> \
--zip-file fileb://function.zip| Event ID | Description |
|---|---|
RDS-EVENT-0088 |
The DB instance has been started |
RDS-EVENT-0087 |
The DB instance has been stopped |
RDS-EVENT-0154 |
The DB instance is being started due to exceeding the maximum allowed time being stopped |
This function triggers on RDS-EVENT-0088. You can also add RDS-EVENT-0154 to the EventBridge pattern to specifically catch the "7-day auto-restart" event.
The function logs in Japanese:
| Log Message | Meaning |
|---|---|
停止コマンドを送信しました |
Stop command sent successfully |
既に停止しています |
Instance is already stopped |
現在停止処理中です |
Instance is currently stopping |
停止できないステータスです |
Instance is in a state that cannot be stopped |
エラーが発生しました |
An error occurred |