Check if RDS Instances Are Protected by a Backup Plan
Overview
This check verifies that your Amazon RDS database instances are included in an AWS Backup plan. AWS Backup provides centralized, automated backup management with scheduled backups, retention policies, and cross-region copy capabilities.
Note: This check applies to non-Aurora RDS instances. Aurora databases are evaluated separately.
Risk
Without a backup plan, your RDS instances are vulnerable to:
- Data loss from accidental deletion or corruption
- Extended outages when recovery is needed but no recent backup exists
- Missed recovery objectives (RPO/RTO) during incidents
- Compliance violations for regulations requiring backup policies
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to manage AWS Backup and IAM roles
- The ARN of the RDS instance you want to protect
How to find your RDS instance ARN
- Go to the RDS Console
- Click Databases in the left menu
- Select your database instance
- In the Configuration tab, find the ARN field
The ARN format is: arn:aws:rds:us-east-1:123456789012:db:my-database
AWS Console Method
-
Open the AWS Backup console at https://console.aws.amazon.com/backup/
-
Enable RDS in AWS Backup (first time only):
- Click Settings in the left menu
- Under Service opt-in, click Configure resources
- Ensure RDS is toggled On
- Click Confirm
-
Create or select a backup plan:
- Click Backup plans in the left menu
- Either select an existing plan or click Create backup plan
- If creating new: choose Build a new plan, give it a name, and configure a backup rule (e.g., daily backups with 35-day retention)
-
Assign your RDS instance to the plan:
- In your backup plan, click Assign resources
- Enter a Resource assignment name (e.g.,
rds-production-db) - For IAM role, select Default role or choose an existing role with backup permissions
- Under Resource selection, choose Include specific resource types
- Select RDS as the resource type
- Choose All instances or select your specific database
- Click Assign resources
-
Your RDS instance is now protected by the backup plan.
AWS CLI (optional)
Step 1: Create a backup vault (if you don't have one)
aws backup create-backup-vault \
--backup-vault-name rds-backup-vault \
--region us-east-1
Step 2: Create a backup plan
aws backup create-backup-plan \
--backup-plan '{
"BackupPlanName": "rds-backup-plan",
"Rules": [{
"RuleName": "DailyBackup",
"TargetBackupVaultName": "rds-backup-vault",
"ScheduleExpression": "cron(0 5 ? * * *)",
"StartWindowMinutes": 60,
"CompletionWindowMinutes": 120,
"Lifecycle": {
"DeleteAfterDays": 35
}
}]
}' \
--region us-east-1
Note the BackupPlanId from the output.
Step 3: Assign the RDS instance to the backup plan
aws backup create-backup-selection \
--backup-plan-id <your-backup-plan-id> \
--backup-selection '{
"SelectionName": "rds-instance-selection",
"IamRoleArn": "arn:aws:iam::<account-id>:role/service-role/AWSBackupDefaultServiceRole",
"Resources": ["arn:aws:rds:us-east-1:<account-id>:db:<your-db-identifier>"]
}' \
--region us-east-1
Replace:
<your-backup-plan-id>with the ID from step 2<account-id>with your AWS account ID<your-db-identifier>with your RDS instance identifier
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS Backup plan for RDS instances
Parameters:
BackupPlanName:
Type: String
Default: rds-backup-plan
Description: Name of the backup plan
RDSInstanceArn:
Type: String
Description: ARN of the RDS instance to protect
Resources:
BackupVault:
Type: AWS::Backup::BackupVault
Properties:
BackupVaultName: !Sub '${BackupPlanName}-vault'
BackupPlan:
Type: AWS::Backup::BackupPlan
Properties:
BackupPlan:
BackupPlanName: !Ref BackupPlanName
BackupPlanRule:
- RuleName: DailyBackup
TargetBackupVault: !Ref BackupVault
ScheduleExpression: cron(0 5 ? * * *)
StartWindowMinutes: 60
CompletionWindowMinutes: 120
Lifecycle:
DeleteAfterDays: 35
BackupRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: backup.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
- arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores
BackupSelection:
Type: AWS::Backup::BackupSelection
Properties:
BackupPlanId: !Ref BackupPlan
BackupSelection:
SelectionName: rds-instance-selection
IamRoleArn: !GetAtt BackupRole.Arn
Resources:
- !Ref RDSInstanceArn
Outputs:
BackupPlanId:
Description: ID of the created backup plan
Value: !Ref BackupPlan
BackupVaultArn:
Description: ARN of the backup vault
Value: !GetAtt BackupVault.BackupVaultArn
Deploy the stack:
aws cloudformation create-stack \
--stack-name rds-backup-protection \
--template-body file://template.yaml \
--parameters ParameterKey=RDSInstanceArn,ParameterValue=arn:aws:rds:us-east-1:123456789012:db:my-database \
--capabilities CAPABILITY_IAM \
--region us-east-1
Terraform (optional)
variable "rds_instance_arn" {
description = "ARN of the RDS instance to protect"
type = string
}
variable "backup_plan_name" {
description = "Name of the backup plan"
type = string
default = "rds-backup-plan"
}
resource "aws_backup_vault" "rds_vault" {
name = "${var.backup_plan_name}-vault"
}
resource "aws_backup_plan" "rds_plan" {
name = var.backup_plan_name
rule {
rule_name = "DailyBackup"
target_vault_name = aws_backup_vault.rds_vault.name
schedule = "cron(0 5 ? * * *)"
start_window = 60
completion_window = 120
lifecycle {
delete_after = 35
}
}
}
resource "aws_iam_role" "backup_role" {
name = "${var.backup_plan_name}-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "backup.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "backup_policy" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
role = aws_iam_role.backup_role.name
}
resource "aws_iam_role_policy_attachment" "restore_policy" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"
role = aws_iam_role.backup_role.name
}
resource "aws_backup_selection" "rds_selection" {
iam_role_arn = aws_iam_role.backup_role.arn
name = "rds-instance-selection"
plan_id = aws_backup_plan.rds_plan.id
resources = [
var.rds_instance_arn
]
}
output "backup_plan_id" {
description = "ID of the created backup plan"
value = aws_backup_plan.rds_plan.id
}
output "backup_vault_arn" {
description = "ARN of the backup vault"
value = aws_backup_vault.rds_vault.arn
}
Deploy:
terraform init
terraform apply -var="rds_instance_arn=arn:aws:rds:us-east-1:123456789012:db:my-database"
Verification
After remediation, verify your RDS instance is protected:
- Go to AWS Backup > Protected resources
- Filter by RDS resource type
- Confirm your database instance appears in the list
CLI verification
List protected resources:
aws backup list-protected-resources \
--region us-east-1 \
--query "Results[?ResourceType=='RDS']"
Check backup jobs for your instance:
aws backup list-backup-jobs \
--by-resource-arn arn:aws:rds:us-east-1:<account-id>:db:<your-db-identifier> \
--region us-east-1
Re-run the Prowler check:
prowler aws --check rds_instance_protected_by_backup_plan --region us-east-1
Additional Resources
- AWS Backup Documentation
- Backing Up and Restoring an Amazon RDS DB Instance
- AWS Backup Pricing
- AWS Backup Best Practices
Notes
-
RDS automated backups vs. AWS Backup: RDS has its own automated backup feature, but AWS Backup provides centralized management, cross-account/cross-region copies, and consistent retention policies across services.
-
Tag-based selection: For managing many databases, consider using tag-based resource selection instead of specifying individual ARNs. Tag all databases that need backup (e.g.,
backup=daily) and configure AWS Backup to select resources by tag. -
Cost considerations: AWS Backup charges for backup storage. Review the pricing page to understand costs for your retention requirements.
-
Recovery testing: Periodically test restoring from backups to ensure your recovery process works as expected.