aws-cloudformation-rds

AWS CloudFormation RDS Database

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "aws-cloudformation-rds" with this command: npx skills add giuseppe-trisciuoglio/developer-kit/giuseppe-trisciuoglio-developer-kit-aws-cloudformation-rds

AWS CloudFormation RDS Database

Overview

Create production-ready Amazon RDS infrastructure using AWS CloudFormation templates. This skill covers RDS instances (MySQL, PostgreSQL, Aurora, MariaDB), DB clusters, multi-AZ deployments, parameter groups, subnet groups, security groups, template structure best practices, parameter patterns, and cross-stack references for modular, reusable infrastructure as code.

When to Use

Use this skill when:

  • Creating new RDS database instances (MySQL, PostgreSQL, Aurora, MariaDB)

  • Configuring DB clusters with read replicas

  • Setting up multi-AZ deployments for high availability

  • Creating DB parameter groups and option groups

  • Configuring DB subnet groups for VPC deployment

  • Implementing template Parameters with AWS-specific types

  • Creating Outputs for cross-stack references

  • Organizing templates with Mappings and Conditions

  • Designing reusable, modular CloudFormation templates

  • Integrating with Secrets Manager for credential management

Quick Start

Basic MySQL RDS Instance

AWSTemplateFormatVersion: 2010-09-09 Description: Simple MySQL RDS instance with basic configuration

Parameters: DBInstanceIdentifier: Type: String Default: mydatabase Description: Database instance identifier

MasterUsername: Type: String Default: admin Description: Master username

MasterUserPassword: Type: String NoEcho: true Description: Master user password

DBInstanceClass: Type: String Default: db.t3.micro AllowedValues: - db.t3.micro - db.t3.small - db.t3.medium

Resources: DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: Subnet group for RDS SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2

DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: !Ref DBInstanceIdentifier DBInstanceClass: !Ref DBInstanceClass Engine: mysql MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup AllocatedStorage: "20" StorageType: gp3 MultiAZ: false

Outputs: DBInstanceEndpoint: Description: Database endpoint address Value: !GetAtt DBInstance.Endpoint.Address

DBInstancePort: Description: Database port Value: !GetAtt DBInstance.Endpoint.Port

Aurora MySQL Cluster

AWSTemplateFormatVersion: 2010-09-09 Description: Aurora MySQL cluster with writer and reader instances

Parameters: DBClusterIdentifier: Type: String Default: my-aurora-cluster Description: Cluster identifier

MasterUsername: Type: String Default: admin

MasterUserPassword: Type: String NoEcho: true

Resources: DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: Subnet group for Aurora SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2

DBCluster: Type: AWS::RDS::DBCluster Properties: DBClusterIdentifier: !Ref DBClusterIdentifier Engine: aurora-mysql MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup DatabaseName: mydb EngineMode: provisioned Port: 3306

DBInstanceWriter: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: !Sub ${DBClusterIdentifier}-writer DBClusterIdentifier: !Ref DBCluster Engine: aurora-mysql DBInstanceClass: db.t3.medium

DBInstanceReader: Type: AWS::RDS::DBInstance DependsOn: DBInstanceWriter Properties: DBInstanceIdentifier: !Sub ${DBClusterIdentifier}-reader DBClusterIdentifier: !Ref DBCluster Engine: aurora-mysql DBInstanceClass: db.t3.medium PromotionTier: 2

Outputs: ClusterEndpoint: Description: Writer endpoint Value: !GetAtt DBCluster.Endpoint

ReaderEndpoint: Description: Reader endpoint Value: !GetAtt DBCluster.ReadEndpoint

Template Structure

Template Sections Overview

AWS CloudFormation templates are JSON or YAML files with specific sections. Each section serves a purpose in defining your infrastructure.

AWSTemplateFormatVersion: 2010-09-09 # Required - template version Description: Optional description string # Optional description

Section order matters for readability but CloudFormation accepts any order

Mappings: {} # Static configuration tables Metadata: {} # Additional information about resources Parameters: {} # Input values for customization Rules: {} # Parameter validation rules Conditions: {} # Conditional resource creation Transform: {} # Macro processing (e.g., AWS::Serverless) Resources: {} # AWS resources to create (REQUIRED) Outputs: {} # Return values after stack creation

Format Version

The AWSTemplateFormatVersion identifies the template version. Current version is 2010-09-09 .

AWSTemplateFormatVersion: 2010-09-09 Description: My RDS Database Template

Description

Add a description to document the template's purpose. Must appear after the format version.

AWSTemplateFormatVersion: 2010-09-09 Description: > This template creates an RDS MySQL instance with:

  • Multi-AZ deployment for high availability
  • Encrypted storage
  • Automated backups
  • Performance Insights enabled

Metadata

Use Metadata for additional information about resources or parameters, including AWS::CloudFormation::Interface for parameter grouping.

Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Database Configuration Parameters: - DBInstanceIdentifier - Engine - DBInstanceClass - Label: default: Credentials Parameters: - MasterUsername - MasterUserPassword - Label: default: Network Parameters: - DBSubnetGroupName - VPCSecurityGroups ParameterLabels: DBInstanceIdentifier: default: Database Instance ID MasterUsername: default: Master Username

Resources Section

The Resources section is the only required section. It defines AWS resources to provision.

Resources:

DB Subnet Group (required for VPC deployment)

DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: Subnet group for RDS deployment SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2

DB Parameter Group

DBParameterGroup: Type: AWS::RDS::DBParameterGroup Properties: Description: Custom parameter group for MySQL Family: mysql8.0 Parameters: max_connections: 200 innodb_buffer_pool_size: 1073741824

DB Instance

DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: mydbinstance DBInstanceClass: db.t3.micro Engine: mysql MasterUsername: admin MasterUserPassword: !Ref DBPassword DBSubnetGroupName: !Ref DBSubnetGroup DBParameterGroupName: !Ref DBParameterGroup

Parameters

Parameter Types

Use AWS-specific parameter types for validation and easier selection in the console.

Parameters:

DB instance identifier

DBInstanceIdentifier: Type: String Description: Database instance identifier

AWS-specific parameter types for validation

DBInstanceClass: Type: AWS::RDS::DBInstance::InstanceType Description: RDS instance class Default: db.t3.micro

Engine version from SSM

EngineVersion: Type: AWS::RDS::DBInstance::Version Description: Database engine version Default: 8.0

For existing VPC security groups

VPCSecurityGroups: Type: List<AWS::EC2::SecurityGroup::Id> Description: Security groups for RDS instance

AWS::RDS::DBInstance::InstanceType Values

Common RDS instance types:

Parameters: DBInstanceClass: Type: String AllowedValues: - db.t3.micro - db.t3.small - db.t3.medium - db.t3.large - db.t3.xlarge - db.t3.2xlarge - db.m5.large - db.m5.xlarge - db.m5.2xlarge - db.m5.4xlarge - db.r5.large - db.r5.xlarge - db.r5.2xlarge

Parameter Constraints

Add constraints to validate parameter values.

Parameters: DBInstanceIdentifier: Type: String Description: Database instance identifier Default: mydatabase AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]*$" ConstraintDescription: Must begin with a letter; contain only alphanumeric characters MinLength: 1 MaxLength: 63

MasterUsername: Type: String Description: Master username Default: admin AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]*$" MinLength: 1 MaxLength: 16 NoEcho: true

MasterUserPassword: Type: String Description: Master user password NoEcho: true MinLength: 8 MaxLength: 41 AllowedPattern: "[a-zA-Z0-9]*"

AllocatedStorage: Type: Number Description: Allocated storage in GB Default: 20 MinValue: 20 MaxValue: 65536

DBPort: Type: Number Description: Database port Default: 3306 MinValue: 1150 MaxValue: 65535

Engine and Version Parameters

Parameters: Engine: Type: String Description: Database engine Default: mysql AllowedValues: - mysql - postgres - oracle-ee - oracle-se2 - sqlserver-ee - sqlserver-se - sqlserver-ex - sqlserver-web - aurora - aurora-mysql - aurora-postgresql - mariadb

EngineVersion: Type: String Description: Database engine version Default: 8.0.35

DBFamily: Type: String Description: Parameter group family Default: mysql8.0 AllowedValues: - mysql5.6 - mysql5.7 - mysql8.0 - postgres11 - postgres12 - postgres13 - postgres14 - postgres15 - postgres16 - aurora5.6 - aurora-mysql5.7 - aurora-mysql8.0 - aurora-postgresql11 - aurora-postgresql14

SSM Parameter Types

Reference Systems Manager parameters for dynamic values.

Parameters: LatestMySQLVersion: Type: AWS::SSM::Parameter::Value<String> Description: Latest MySQL version from SSM Default: /rds/mysql/latest/version

LatestPostgreSQLVersion: Type: AWS::SSM::Parameter::Value<String> Description: Latest PostgreSQL version from SSM Default: /rds/postgres/latest/version

NoEcho for Sensitive Data

Use NoEcho for passwords and sensitive values to mask them in console output.

Parameters: MasterUserPassword: Type: String Description: Master user password NoEcho: true MinLength: 8 MaxLength: 41

Mappings

Use Mappings for static configuration data based on regions or instance types.

Mappings: InstanceTypeConfig: db.t3.micro: CPU: 2 MemoryGiB: 1 StorageGB: 20 db.t3.small: CPU: 2 MemoryGiB: 2 StorageGB: 20 db.t3.medium: CPU: 2 MemoryGiB: 4 StorageGB: 20 db.m5.large: CPU: 2 MemoryGiB: 8 StorageGB: 100

RegionDatabasePort: us-east-1: MySQL: 3306 PostgreSQL: 5432 us-west-2: MySQL: 3306 PostgreSQL: 5432 eu-west-1: MySQL: 3306 PostgreSQL: 5432

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceClass: !FindInMap [InstanceTypeConfig, !Ref DBInstanceClass, CPU] Engine: mysql # ...

Conditions

Use Conditions to conditionally create resources based on parameters.

Parameters: EnableMultiAZ: Type: String Default: false AllowedValues: - true - false

EnableEncryption: Type: String Default: true AllowedValues: - true - false

Environment: Type: String Default: development AllowedValues: - development - staging - production

Conditions: IsMultiAZ: !Equals [!Ref EnableMultiAZ, true] IsEncrypted: !Equals [!Ref EnableEncryption, true] IsProduction: !Equals [!Ref Environment, production]

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: MultiAZ: !Ref EnableMultiAZ StorageEncrypted: !Ref EnableEncryption # Production gets automated backups BackupRetentionPeriod: !If [IsProduction, 35, 7] DeletionProtection: !If [IsProduction, true, false]

Condition Functions

Conditions: IsDev: !Equals [!Ref Environment, development] IsStaging: !Equals [!Ref Environment, staging] IsProduction: !Equals [!Ref Environment, production]

HasLicense: !Not [!Condition IsDev]

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: # Use license-included for production LicenseModel: !If [HasLicense, "license-included", "bring-your-own-license"] # Production uses provisioned IOPS StorageType: !If [IsProduction, "io1", "gp3"] Iops: !If [IsProduction, 3000, !Ref AWS::NoValue]

Transform

Use Transform for macros like AWS::Serverless for SAM templates.

AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Description: Serverless RDS application template

Globals: Function: Timeout: 30 Runtime: python3.11

Resources: RDSFunction: Type: AWS::Serverless::Function Properties: Handler: app.handler CodeUri: function/ Policies: - RDSFullAccessPolicy: DBInstanceIdentifier: !Ref DBInstanceIdentifier Environment: Variables: DB_HOST: !GetAtt DBInstance.Endpoint.Address DB_NAME: !Ref DBName DB_USER: !Ref MasterUsername

Outputs and Cross-Stack References

Basic Outputs

Outputs: DBInstanceId: Description: Database Instance ID Value: !Ref DBInstance

DBInstanceEndpoint: Description: Database endpoint address Value: !GetAtt DBInstance.Endpoint.Address

DBInstancePort: Description: Database port Value: !GetAtt DBInstance.Endpoint.Port

DBInstanceArn: Description: Database Instance ARN Value: !GetAtt DBInstance.Arn

DBInstanceClass: Description: Database Instance Class Value: !Ref DBInstanceClass

Exporting Values for Cross-Stack References

Export values so other stacks can import them.

Outputs: DBInstanceId: Description: Database Instance ID for other stacks Value: !Ref DBInstance Export: Name: !Sub ${AWS::StackName}-DBInstanceId

DBInstanceEndpoint: Description: Database endpoint for application stacks Value: !GetAtt DBInstance.Endpoint.Address Export: Name: !Sub ${AWS::StackName}-DBEndpoint

DBInstancePort: Description: Database port for application stacks Value: !GetAtt DBInstance.Endpoint.Port Export: Name: !Sub ${AWS::StackName}-DBPort

DBConnectionString: Description: Full connection string for applications Value: !Sub jdbc:mysql://${DBInstanceEndpoint}:${DBInstancePort}/${DBName} Export: Name: !Sub ${AWS::StackName}-DBConnectionString

Importing Values in Another Stack

Parameters:

Import via AWS::RDS::DBInstance::Id for console selection

DBInstanceId: Type: AWS::RDS::DBInstance::Id Description: RDS instance ID from database stack

Or use Fn::ImportValue for programmatic access

DBEndpoint: Type: String Description: Database endpoint address

Resources: ApplicationDatabaseConfig: Type: AWS::SSM::Parameter Properties: Name: /app/database/endpoint Value: !Ref DBEndpoint Type: String

Cross-Stack Reference Pattern

Create a dedicated database stack that exports values:

database-stack.yaml

AWSTemplateFormatVersion: 2010-09-09 Description: Database infrastructure stack

Parameters: EnvironmentName: Type: String Default: production

Resources: DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: !Sub Subnet group for ${EnvironmentName} SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2

DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceClass.t3.medium: db Engine: mysql MasterUsername: admin MasterUserPassword: !Ref DBPassword DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup MultiAZ: true StorageEncrypted: true

Outputs: DBInstanceId: Value: !Ref DBInstance Export: Name: !Sub ${EnvironmentName}-DBInstanceId

DBEndpoint: Value: !GetAtt DBInstance.Endpoint.Address Export: Name: !Sub ${EnvironmentName}-DBEndpoint

DBArn: Value: !GetAtt DBInstance.Arn Export: Name: !Sub ${EnvironmentName}-DBArn

DBSubnetGroupName: Value: !Ref DBSubnetGroup Export: Name: !Sub ${EnvironmentName}-DBSubnetGroupName

Application stack imports these values:

application-stack.yaml

AWSTemplateFormatVersion: 2010-09-09 Description: Application stack that imports from database stack

Parameters: DatabaseStackName: Type: String Description: Name of the database stack Default: database-stack

Resources: ApplicationConfig: Type: AWS::SSM::Parameter Properties: Name: /app/database/endpoint Value: !ImportValue Fn::Sub: ${DatabaseStackName}-DBEndpoint Type: String

LambdaFunction: Type: AWS::Lambda::Function Properties: Runtime: python3.11 Handler: app.handler Environment: Variables: DB_ENDPOINT: !ImportValue Fn::Sub: ${DatabaseStackName}-DBEndpoint

RDS Database Components

DB Subnet Group

Required for VPC deployment. Must include at least 2 subnets in different AZs.

Resources: DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: Subnet group for RDS instance SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !Ref PrivateSubnet3 Tags: - Key: Name Value: !Sub ${AWS::StackName}-dbsubnet

DB Parameter Group

Custom parameter groups for database configuration.

Resources: DBParameterGroup: Type: AWS::RDS::DBParameterGroup Properties: Description: Custom parameter group for MySQL 8.0 Family: mysql8.0 Parameters: # Connection settings max_connections: 200 max_user_connections: 200

    # Memory settings
    innodb_buffer_pool_size: 1073741824
    innodb_buffer_pool_instances: 4

    # Query cache (MySQL 5.7)
    query_cache_type: 1
    query_cache_size: 268435456

    # Timezone
    default_time_zone: "+00:00"

    # Character set
    character_set_server: utf8mb4
    collation_server: utf8mb4_unicode_ci

  Tags:
    - Key: Name
      Value: !Sub ${AWS::StackName}-dbparam

DB Option Group

For database features like Oracle XML or SQL Server features.

Resources: DBOptionGroup: Type: AWS::RDS::DBOptionGroup Properties: EngineName: oracle-ee MajorEngineVersion: "19" OptionGroupDescription: Option group for Oracle 19c Options: - OptionName: OEM OptionVersion: "19" Port: 5500 VpcSecurityGroupMemberships: - !Ref OEMSecurityGroup - OptionName: SSL OptionSettings: - Name: SQLNET.SSL_VERSION Value: "1.2"

DB Instance - MySQL

Resources: MySQLDBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: mysql-instance DBInstanceClass: db.t3.medium Engine: mysql EngineVersion: "8.0.35" MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword AllocatedStorage: "100" StorageType: gp3 DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup DBParameterGroupName: !Ref DBParameterGroup StorageEncrypted: true MultiAZ: true BackupRetentionPeriod: 35 DeletionProtection: true EnablePerformanceInsights: true PerformanceInsightsRetentionPeriod: 731 AutoMinorVersionUpgrade: false Tags: - Key: Environment Value: !Ref Environment

DB Instance - PostgreSQL

Resources: PostgreSQLDBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: postgres-instance DBInstanceClass: db.t3.medium Engine: postgres EngineVersion: "16.1" MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword AllocatedStorage: "100" StorageType: gp3 DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup DBParameterGroupName: !Ref DBParameterGroup StorageEncrypted: true MultiAZ: true BackupRetentionPeriod: 35 DeletionProtection: true EnablePerformanceInsights: true PubliclyAccessible: false

Aurora MySQL Cluster

Resources: AuroraMySQLCluster: Type: AWS::RDS::DBCluster Properties: DBClusterIdentifier: aurora-mysql-cluster Engine: aurora-mysql EngineVersion: "8.0.mysql_aurora.3.02.0" MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword DatabaseName: mydb DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup DBClusterParameterGroupName: !Ref AuroraClusterParameterGroup StorageEncrypted: true EngineMode: provisioned Port: 3306 EnableIAMDatabaseAuthentication: true

AuroraDBInstanceWriter: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: aurora-writer DBClusterIdentifier: !Ref AuroraMySQLCluster Engine: aurora-mysql DBInstanceClass: db.r5.large PromotionTier: 1

AuroraDBInstanceReader: Type: AWS::RDS::DBInstance DependsOn: AuroraDBInstanceWriter Properties: DBInstanceIdentifier: aurora-reader DBClusterIdentifier: !Ref AuroraMySQLCluster Engine: aurora-mysql DBInstanceClass: db.r5.large PromotionTier: 2

Aurora PostgreSQL Cluster

Resources: AuroraPostgresCluster: Type: AWS::RDS::DBCluster Properties: DBClusterIdentifier: aurora-pg-cluster Engine: aurora-postgresql EngineVersion: "15.4" MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword DatabaseName: mydb DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup StorageEncrypted: true EngineMode: provisioned Port: 5432

AuroraPostgresInstanceWriter: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: aurora-pg-writer DBClusterIdentifier: !Ref AuroraPostgresCluster Engine: aurora-postgresql DBInstanceClass: db.r5.large PromotionTier: 1

AuroraPostgresInstanceReader: Type: AWS::RDS::DBInstance DependsOn: AuroraPostgresInstanceWriter Properties: DBInstanceIdentifier: aurora-pg-reader DBClusterIdentifier: !Ref AuroraPostgresCluster Engine: aurora-postgresql DBInstanceClass: db.r5.large PromotionTier: 2

Aurora Serverless Cluster

Resources: AuroraServerlessCluster: Type: AWS::RDS::DBCluster Properties: DBClusterIdentifier: aurora-serverless Engine: aurora-mysql EngineVersion: "5.6.mysql_aurora.2.12.0" MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword DatabaseName: mydb DBSubnetGroupName: !Ref DBSubnetGroup VPCSecurityGroups: - !Ref DBSecurityGroup EngineMode: serverless ScalingConfiguration: AutoPause: true MinCapacity: 2 MaxCapacity: 32 SecondsUntilAutoPause: 300

DB Cluster Parameter Group (Aurora)

Resources: AuroraClusterParameterGroup: Type: AWS::RDS::DBClusterParameterGroup Properties: Description: Custom cluster parameter group for Aurora MySQL Family: aurora-mysql8.0 Parameters: character_set_server: utf8mb4 collation_server: utf8mb4_unicode_ci max_connections: 1000 innodb_buffer_pool_size: 2147483648 slow_query_log: "ON" long_query_time: 2

Security and Secrets

Using Secrets Manager for Credentials

Resources: DBCredentialsSecret: Type: AWS::SecretsManager::Secret Properties: Name: !Sub ${AWS::StackName}/rds/credentials Description: RDS database credentials SecretString: !Sub | { "username": "${MasterUsername}", "password": "${MasterUserPassword}", "host": !GetAtt DBInstance.Endpoint.Address, "port": !GetAtt DBInstance.Endpoint.Port, "dbname": "mydb" }

DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceClass: db.t3.medium Engine: mysql MasterUsername: !Sub "{{resolve:secretsmanager:${DBCredentialsSecret}:SecretString:username}}" MasterUserPassword: !Sub "{{resolve:secretsmanager:${DBCredentialsSecret}:SecretString:password}}" # ...

DB Security Group (for EC2-Classic)

Resources: DBSecurityGroup: Type: AWS::RDS::DBSecurityGroup Properties: DBSecurityGroupDescription: Security group for RDS instance EC2VpcId: !Ref VPCId # For EC2-Classic, use DBSecurityGroupIngress DBSecurityGroupIngress: - EC2SecurityGroupId: !Ref AppSecurityGroup - EC2SecurityGroupName: default

VPC Security Groups (Recommended)

For VPC deployment, use EC2 security groups instead:

Resources: DBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for RDS VpcId: !Ref VPCId GroupName: !Sub ${AWS::StackName}-rds-sg SecurityGroupIngress: - IpProtocol: tcp FromPort: 3306 ToPort: 3306 SourceSecurityGroupId: !Ref AppSecurityGroup Tags: - Key: Name Value: !Sub ${AWS::StackName}-rds-sg

AppSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for application VpcId: !Ref VPCId SecurityGroupEgress: - IpProtocol: tcp FromPort: 3306 ToPort: 3306 DestinationSecurityGroupId: !Ref DBSecurityGroup

High Availability and Multi-AZ

Multi-AZ Deployment

Parameters: EnableMultiAZ: Type: String Default: true AllowedValues: - true - false

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: # Multi-AZ is not supported for Aurora clusters (automatic) MultiAZ: !Ref EnableMultiAZ # For multi-AZ, use a standby in a different AZ AvailabilityZone: !If - IsMultiAZ - !Select [1, !GetAZs ''] - !Ref AWS::NoValue # For single-AZ, specify no AZ (AWS selects)

Read Replicas

Resources:

Primary instance

PrimaryDBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceClass: db.r5.large Engine: mysql SourceDBInstanceIdentifier: !Ref ExistingDBInstance

Read replica in different region

CrossRegionReadReplica: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: my-cross-region-replica SourceDBInstanceIdentifier: !Sub arn:aws:rds:us-west-2:${AWS::AccountId}:db:${PrimaryDBInstance} DBInstanceClass: db.r5.large Engine: mysql

Enhanced Monitoring and Performance Insights

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: EnablePerformanceInsights: true PerformanceInsightsRetentionPeriod: 731 PerformanceInsightsKMSKeyId: !Ref PerformanceInsightsKey

  # Enhanced Monitoring
  MonitoringInterval: 60
  MonitoringRoleArn: !GetAtt MonitoringRole.Arn

  # Database insights
  EnableCloudwatchLogsExports:
    - audit
    - error
    - general
    - slowquery

IAM Role for Enhanced Monitoring

Resources: MonitoringRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: monitoring.rds.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole

Best Practices

Use AWS-Specific Parameter Types

Always use AWS-specific parameter types for validation and easier selection.

Parameters: DBInstanceClass: Type: AWS::RDS::DBInstance::InstanceType Description: RDS instance type

DBInstanceIdentifier: Type: String AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]*$"

Enable Encryption at Rest

Always enable encryption for production databases.

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: StorageEncrypted: true KmsKeyId: !Ref EncryptionKey

Use Multi-AZ for Production

Conditions: IsProduction: !Equals [!Ref Environment, production]

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: MultiAZ: !If [IsProduction, true, false] BackupRetentionPeriod: !If [IsProduction, 35, 7] DeletionProtection: !If [IsProduction, true, false]

Enable Performance Insights

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: EnablePerformanceInsights: true PerformanceInsightsRetentionPeriod: 731 PerformanceInsightsKMSKeyId: !Ref PK

Use Proper Naming Conventions

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: Tags: - Key: Name Value: !Sub ${Environment}-${Application}-rds - Key: Environment Value: !Ref Environment - Key: Application Value: !Ref ApplicationName - Key: ManagedBy Value: CloudFormation

Use Secrets Manager for Credentials

Resources: DBCredentials: Type: AWS::SecretsManager::Secret Properties: Name: !Sub ${AWS::StackName}/rds/credentials SecretString: !Sub '{"username":"${MasterUsername}","password":"${MasterUserPassword}"}'

DBInstance: Type: AWS::RDS::DBInstance Properties: MasterUsername: !Sub "{{resolve:secretsmanager:${DBCredentials}:SecretString:username}}" MasterUserPassword: !Sub "{{resolve:secretsmanager:${DBCredentials}:SecretString:password}}"

Separate Database and Application Stacks

database-stack.yaml - Rarely changes

AWSTemplateFormatVersion: 2010-09-09 Description: Database infrastructure (VPC, subnets, RDS instance) Resources: DBSubnetGroup: AWS::RDS::DBSubnetGroup DBInstance: AWS::RDS::DBInstance DBParameterGroup: AWS::RDS::DBParameterGroup

application-stack.yaml - Changes frequently

AWSTemplateFormatVersion: 2010-09-09 Description: Application resources Parameters: DatabaseStackName: Type: String Resources: ApplicationConfig: AWS::SSM::Parameter

Use Pseudo Parameters

Use pseudo parameters for region-agnostic templates.

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: !Sub ${AWS::StackName}-${AWS::Region} Tags: - Key: Region Value: !Ref AWS::Region - Key: AccountId Value: !Ref AWS::AccountId

Validate Before Deployment

Validate template

aws cloudformation validate-template --template-body file://template.yaml

Use cfn-lint for advanced validation

pip install cfn-lint cfn-lint template.yaml

Check for AWS-specific issues

cfn-lint template.yaml --region us-east-1

Stack Policies

Stack policies protect critical resources from unintended updates during stack operations. For RDS databases, this is essential to prevent accidental modifications that could cause data loss or downtime.

Basic Stack Policy

{ "Statement" : [ { "Effect" : "Allow", "Action" : "Update:", "Principal": "", "Resource" : "" }, { "Effect" : "Deny", "Action" : "Update:", "Principal": "", "Resource" : "LogicalResourceId/DBInstance" }, { "Effect" : "Deny", "Action" : "Update:", "Principal": "*", "Resource" : "LogicalResourceId/DBCluster" } ] }

Stack Policy for Production RDS

{ "Statement": [ { "Effect": "Allow", "Action": "Update:", "Principal": "", "Resource": "" }, { "Effect": "Deny", "Action": [ "Update:Replace", "Update:Delete" ], "Principal": "", "Resource": "LogicalResourceId/DBInstance" }, { "Effect": "Deny", "Action": [ "Update:Replace", "Update:Delete" ], "Principal": "", "Resource": "LogicalResourceId/DBCluster" }, { "Effect": "Deny", "Action": "Update:Delete", "Principal": "", "Resource": "LogicalResourceId/DBSubnetGroup" }, { "Effect": "Allow", "Action": "Update:Modify", "Principal": "*", "Resource": "LogicalResourceId/DBInstance", "Condition": { "StringEquals": { "ResourceAttribute/StorageEncrypted": "true" } } } ] }

Setting Stack Policy

Set stack policy during creation

aws cloudformation create-stack
--stack-name my-rds-stack
--template-body file://template.yaml
--stack-policy-body file://stack-policy.json

Set stack policy on existing stack

aws cloudformation set-stack-policy
--stack-name my-rds-stack
--stack-policy-body file://stack-policy.json

View current stack policy

aws cloudformation get-stack-policy
--stack-name my-rds-stack
--query StackPolicyBody
--output text

Termination Protection

Termination protection is critical for RDS databases as it prevents accidental deletion that could result in data loss. This should be enabled for all production databases.

Enabling Termination Protection

Enable termination protection on stack creation

aws cloudformation create-stack
--stack-name production-rds
--template-body file://template.yaml
--enable-termination-protection

Enable termination protection on existing stack

aws cloudformation update-termination-protection
--stack-name production-rds
--enable-termination-protection

Check if termination protection is enabled

aws cloudformation describe-stacks
--stack-name production-rds
--query 'Stacks[0].EnableTerminationProtection'
--output boolean

Disable termination protection (requires confirmation)

aws cloudformation update-termination-protection
--stack-name production-rds
--no-enable-termination-protection

Termination Protection in Template

AWSTemplateFormatVersion: 2010-09-09 Description: RDS instance with termination protection enabled

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: production-db DBInstanceClass: db.r5.large Engine: mysql MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword StorageEncrypted: true MultiAZ: true DeletionProtection: true # Termination protection is set at stack level, not resource level

Deletion Protection vs Termination Protection

Feature DeletionProtection Termination Protection

Level Resource level (DBInstance) Stack level

Prevents DELETE_DB_INSTANCE API call CloudFormation stack deletion

Console UI Instance settings Stack settings

Override Cannot be overridden Can be disabled with confirmation

Recommended for All production RDS instances All production stacks with RDS

Deletion Protection Best Practice

Conditions: IsProduction: !Equals [!Ref Environment, production]

Resources: DBInstance: Type: AWS::RDS::DBInstance Properties: # Always enable deletion protection DeletionProtection: !If [IsProduction, true, false] # Additional production safeguards MultiAZ: !If [IsProduction, true, false] BackupRetentionPeriod: !If [IsProduction, 35, 7]

Drift Detection

Drift detection identifies when the actual infrastructure configuration differs from the CloudFormation template. This is crucial for RDS to ensure security and compliance.

Detecting Drift

Detect drift on entire stack

aws cloudformation detect-stack-drift
--stack-name production-rds

Detect drift on specific resources

aws cloudformation detect-stack-drift
--stack-name production-rds
--logical-resource-ids DBInstance,DBParameterGroup

Get drift detection status

aws cloudformation describe-stack-drift-detection-status
--stack-drift-detection-id <detection-id>

Check drift status for all resources

aws cloudformation describe-stack-resource-drifts
--stack-name production-rds

Drift Detection Status Response

{ "StackResourceDrifts": [ { "LogicalResourceId": "DBInstance", "PhysicalResourceId": "production-db-instance-id", "ResourceType": "AWS::RDS::DBInstance", "StackId": "arn:aws:cloudformation:us-east-1:123456789:stack/production-rds/...", "DriftStatus": "MODIFIED", "PropertyDifferences": [ { "PropertyPath": "MultiAZ", "ExpectedValue": "true", "ActualValue": "false" }, { "PropertyPath": "BackupRetentionPeriod", "ExpectedValue": "35", "ActualValue": "7" } ] } ] }

Automated Drift Detection Schedule

Create a Lambda function to check drift weekly

and send SNS notification if drift is detected

aws events put-rule
--name rds-drift-detection
--schedule-expression "rate(7 days)"

aws events put-targets
--rule rds-drift-detection
--targets "Id"="1","Arn"="arn:aws:lambda:us-east-1:123456789:function/drift-checker"

Drift Detection Script

#!/bin/bash

check-rds-drift.sh

STACK_NAME=$1 DRIFT_STATUS=$(aws cloudformation detect-stack-drift
--stack-name $STACK_NAME
--query StackDriftStatus
--output text 2>/dev/null)

if [ "$DRIFT_STATUS" == "DRIFTED" ]; then echo "Drift detected on stack $STACK_NAME" aws cloudformation describe-stack-resources
--stack-name $STACK_NAME
--query 'StackResources[?ResourceStatusReason!=null]'
--output table

Send notification

aws sns publish
--topic-arn arn:aws:sns:us-east-1:123456789:rds-drift-alert
--message "Drift detected on stack $STACK_NAME" else echo "No drift detected on stack $STACK_NAME" fi

Change Sets

Change sets allow you to preview how proposed changes will affect your stack before execution. This is essential for RDS to understand potential impact.

Creating and Viewing a Change Set

Create change set for stack update

aws cloudformation create-change-set
--stack-name production-rds
--change-set-name preview-changes
--template-body file://updated-template.yaml
--capabilities CAPABILITY_IAM
--change-set-type UPDATE

List change sets for a stack

aws cloudformation list-change-sets
--stack-name production-rds

Describe change set

aws cloudformation describe-change-set
--stack-name production-rds
--change-set-name preview-changes

Execute change set

aws cloudformation execute-change-set
--stack-name production-rds
--change-set-name preview-changes

Delete change set (if not executing)

aws cloudformation delete-change-set
--stack-name production-rds
--change-set-name preview-changes

Change Set Response Example

{ "ChangeSetName": "preview-changes", "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789:changeSet/...", "StackId": "arn:aws:cloudformation:us-east-1:123456789:stack/...", "Status": "CREATE_COMPLETE", "Changes": [ { "Type": "Resource", "ResourceChange": { "Action": "Modify", "LogicalResourceId": "DBInstance", "PhysicalResourceId": "production-db", "ResourceType": "AWS::RDS::DBInstance", "Replacement": "False", "Scope": [ "Properties" ], "Details": [ { "Target": { "Attribute": "Properties", "Name": "MultiAZ" }, "Evaluation": "Static", "ChangeSource": "Parameter", "BeforeValue": "false", "AfterValue": "true" } ] } } ] }

Change Set for RDS Modifications

Change set that will modify RDS instance class

aws cloudformation create-change-set
--stack-name production-rds
--change-set-name modify-instance-class
--template-body file://modify-instance-template.yaml
--parameters parameter-overrides DBInstanceClass=db.r5.xlarge

Change set for adding read replica

aws cloudformation create-change-set
--stack-name production-rds
--change-set-name add-read-replica
--template-body file://add-replica-template.yaml

Change set that requires replacement (causes downtime)

aws cloudformation create-change-set
--stack-name production-rds
--change-set-name change-engine-version
--template-body file://change-version-template.yaml

Change Set Types

Change Set Type Description Use Case

UPDATE

Creates changes for existing stack Modifying existing resources

CREATE

Simulates stack creation Validating new templates

IMPORT

Imports existing resources Moving resources to CloudFormation

Change Set Best Practices for RDS

Always create change set before updating RDS

aws cloudformation create-change-set
--stack-name production-rds
--change-set-name pre-update-preview
--template-body file://updated-template.yaml

Review changes carefully

aws cloudformation describe-change-set
--stack-name production-rds
--change-set-name pre-update-preview
--query 'Changes[].ResourceChange'

Check for replacement operations

aws cloudformation describe-change-set
--stack-name production-rds
--change-set-name pre-update-preview
--query 'Changes[?ResourceChange.Replacement==True]'

Only execute if changes are acceptable

aws cloudformation execute-change-set
--stack-name production-rds
--change-set-name pre-update-preview

Related Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

shadcn-ui

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

tailwind-css-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

unit-test-bean-validation

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

react-patterns

No summary provided by upstream source.

Repository SourceNeeds Review