|
| 1 | +--- |
| 2 | +# Copyright 2018 widdix GmbH |
| 3 | +# |
| 4 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +# you may not use this file except in compliance with the License. |
| 6 | +# You may obtain a copy of the License at |
| 7 | +# |
| 8 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +# |
| 10 | +# Unless required by applicable law or agreed to in writing, software |
| 11 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +# See the License for the specific language governing permissions and |
| 14 | +# limitations under the License. |
| 15 | +AWSTemplateFormatVersion: '2010-09-09' |
| 16 | +Description: 'State: RDS Aurora Serverless v2 PostgreSQL, a cloudonaut.io template, contributed by https://github.com/ab77' |
| 17 | + |
| 18 | +Metadata: |
| 19 | + 'AWS::CloudFormation::Interface': |
| 20 | + ParameterGroups: |
| 21 | + - Label: |
| 22 | + default: 'Parent Stacks' |
| 23 | + Parameters: |
| 24 | + - ParentVPCStack |
| 25 | + - ParentClientStack |
| 26 | + - ParentKmsKeyStack |
| 27 | + - ParentZoneStack |
| 28 | + - ParentSSHBastionStack |
| 29 | + - ParentAlertStack |
| 30 | + - ParentSecretStack |
| 31 | + - Label: |
| 32 | + default: 'RDS Parameters' |
| 33 | + Parameters: |
| 34 | + - CACertificateIdentifier |
| 35 | + - DBBackupRetentionPeriod |
| 36 | + - DBClusterParameterGroupName |
| 37 | + - DBMasterUsername |
| 38 | + - DBMasterUserPassword |
| 39 | + - DBName |
| 40 | + - DBPort |
| 41 | + - DBParameterGroupName |
| 42 | + - DBSnapshotIdentifier |
| 43 | + - EnableDataApi |
| 44 | + - EngineVersion |
| 45 | + - PerformanceInsightsRetentionPeriod |
| 46 | + - PreferredBackupWindow |
| 47 | + - PreferredMaintenanceWindow |
| 48 | + - SubDomainNameWithDot |
| 49 | + - Label: |
| 50 | + default: 'Serverless Parameters' |
| 51 | + Parameters: |
| 52 | + - MaxCapacity |
| 53 | + - MinCapacity |
| 54 | +Parameters: |
| 55 | + ParentVPCStack: |
| 56 | + Description: 'Stack name of parent VPC stack based on vpc/vpc-*azs.yaml template.' |
| 57 | + Type: String |
| 58 | + ParentClientStack: |
| 59 | + Description: 'Stack name of parent client stack based on state/client-sg.yaml template.' |
| 60 | + Type: String |
| 61 | + ParentKmsKeyStack: |
| 62 | + Description: 'Stack name of parent KMS key stack based on security/kms-key.yaml template (ignored when DBSnapshotIdentifier is set, value used from snapshot).' |
| 63 | + Type: String |
| 64 | + Default: '' |
| 65 | + ParentZoneStack: |
| 66 | + Description: 'Optional stack name of parent zone stack based on vpc/vpc-zone-*.yaml template.' |
| 67 | + Type: String |
| 68 | + Default: '' |
| 69 | + ParentSSHBastionStack: |
| 70 | + Description: 'Optional but recommended stack name of parent SSH bastion host/instance stack based on vpc/vpc-*-bastion.yaml template.' |
| 71 | + Type: String |
| 72 | + Default: '' |
| 73 | + ParentAlertStack: |
| 74 | + Description: 'Optional but recommended stack name of parent alert stack based on operations/alert.yaml template.' |
| 75 | + Type: String |
| 76 | + Default: '' |
| 77 | + PerformanceInsightsRetentionPeriod: |
| 78 | + Description: 'Retention period in days for Performance Insights.' |
| 79 | + Type: String |
| 80 | + Default: 341 |
| 81 | + AllowedValues: [7, 93, 341, 589, 731] |
| 82 | + DBSnapshotIdentifier: |
| 83 | + Description: 'Optional identifier for the DB cluster snapshot from which you want to restore (leave blank to create an empty cluster).' |
| 84 | + Type: String |
| 85 | + Default: '' |
| 86 | + ParentSecretStack: |
| 87 | + Description: 'Optional Stack name of parent SecretsManager Secret Stack based on state/secretsmanager-dbsecret.yaml template.' |
| 88 | + Type: String |
| 89 | + Default: '' |
| 90 | + DBName: |
| 91 | + Description: 'Name of the database (ignored when DBSnapshotIdentifier is set, value used from snapshot).' |
| 92 | + Type: String |
| 93 | + Default: '' |
| 94 | + DBBackupRetentionPeriod: |
| 95 | + Description: 'The number of days to keep snapshots of the cluster.' |
| 96 | + Type: Number |
| 97 | + MinValue: 1 |
| 98 | + MaxValue: 35 |
| 99 | + Default: 30 |
| 100 | + DBMasterUsername: |
| 101 | + Description: 'The master user name for the DB instance (ignored when DBSnapshotIdentifier is set, value used from snapshot).' |
| 102 | + Type: 'String' |
| 103 | + Default: master |
| 104 | + DBMasterUserPassword: |
| 105 | + Description: 'The master password for the DB instance (ignored when DBSnapshotIdentifier is set, value used from snapshot. Also ignored when ParentSecretStack is used).' |
| 106 | + Type: String |
| 107 | + NoEcho: true |
| 108 | + Default: '' |
| 109 | + DBClusterParameterGroupName: |
| 110 | + Description: 'The name of the DB cluster parameter group to associate with this DB cluster.' |
| 111 | + Type: String |
| 112 | + Default: '' |
| 113 | + DBParameterGroupName: |
| 114 | + Description: 'The name of an existing DB parameter group.' |
| 115 | + Type: String |
| 116 | + Default: '' |
| 117 | + DBPort: |
| 118 | + Description: 'The port number on which the instances in the DB cluster accept connections.' |
| 119 | + Type: Number |
| 120 | + Default: 5432 |
| 121 | + SubDomainNameWithDot: |
| 122 | + Description: 'Name that is used to create the DNS entry with trailing dot, e.g. §{SubDomainNameWithDot}§{HostedZoneName}. Leave blank for naked (or apex and bare) domain. Requires ParentZoneStack parameter!' |
| 123 | + Type: String |
| 124 | + Default: 'aurora.' |
| 125 | + PreferredBackupWindow: |
| 126 | + Description: 'IGNORED BECAUSE OF A BUG IN CLOUDFORMATION! VALUE WILL APPLY IN THE FUTURE! The daily time range in UTC during which you want to create automated backups.' # TODO remove uppercase warning |
| 127 | + Type: String |
| 128 | + Default: '09:54-10:24' |
| 129 | + PreferredMaintenanceWindow: |
| 130 | + Description: 'IGNORED BECAUSE OF A BUG IN CLOUDFORMATION! VALUE WILL APPLY IN THE FUTURE! The weekly time range (in UTC) during which system maintenance can occur.' # TODO remove uppercase warning |
| 131 | + Type: String |
| 132 | + Default: 'sat:07:00-sat:07:30' |
| 133 | + EnableDataApi: |
| 134 | + Description: 'Enable the Data API (https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html).' |
| 135 | + Type: String |
| 136 | + AllowedValues: ['true', 'false'] |
| 137 | + Default: 'false' |
| 138 | + MaxCapacity: |
| 139 | + Description: 'The maximum capacity units for a Serverless Aurora cluster.' |
| 140 | + Type: String |
| 141 | + AllowedValues: [1, 2, 4, 8, 16, 32, 64, 128] |
| 142 | + Default: 1 |
| 143 | + MinCapacity: |
| 144 | + Description: 'The minimum capacity units for a Serverless Aurora cluster.' |
| 145 | + Type: String |
| 146 | + AllowedValues: [0.5, 1, 2, 4, 8, 16, 32, 64, 128] |
| 147 | + Default: 0.5 |
| 148 | + EngineVersion: |
| 149 | + Description: 'Aurora Serverless v2 PostgreSQL version.' |
| 150 | + Type: String |
| 151 | + AllowedValues: ['15.5', '14.10', '13.13'] # aws rds describe-orderable-db-instance-options --engine aurora-postgresql --db-instance-class db.serverless --query 'OrderableDBInstanceOptions[].[EngineVersion]' --output text |
| 152 | + CACertificateIdentifier: |
| 153 | + Description: 'The identifier of the CA certificate for this DB instance.' |
| 154 | + Type: String |
| 155 | + AllowedValues: ['rds-ca-rsa2048-g1', 'rds-ca-rsa4096-g1', 'rds-ca-ecc384-g1'] # https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.SSL-certificate-rotation.html |
| 156 | + Default: 'rds-ca-ecc384-g1' |
| 157 | +Mappings: |
| 158 | + EngineVersionMap: |
| 159 | + '15.5': |
| 160 | + ClusterParameterGroupFamily: 'aurora-postgresql15' |
| 161 | + '14.10': |
| 162 | + ClusterParameterGroupFamily: 'aurora-postgresql14' |
| 163 | + '13.13': |
| 164 | + ClusterParameterGroupFamily: 'aurora-postgresql13' |
| 165 | +Conditions: |
| 166 | + HasAlertTopic: !Not [!Equals [!Ref ParentAlertStack, '']] |
| 167 | + HasDBClusterParameterGroup: !Not [!Equals [!Ref DBClusterParameterGroupName, '']] |
| 168 | + HasDBParameterGroup: !Not [!Equals [!Ref DBParameterGroupName, '']] |
| 169 | + HasDBSnapshotIdentifier: !Not [!Condition HasNotDBSnapshotIdentifier] |
| 170 | + HasNotDBClusterParameterGroup: !Not [!Condition HasDBClusterParameterGroup] |
| 171 | + HasNotDBParameterGroup: !Not [!Condition HasDBParameterGroup] |
| 172 | + HasNotDBSnapshotIdentifier: !Equals [!Ref DBSnapshotIdentifier, ''] |
| 173 | + HasSecret: !Not [!Equals [!Ref ParentSecretStack, '']] |
| 174 | + HasSSHBastionSecurityGroup: !Not [!Equals [!Ref ParentSSHBastionStack, '']] |
| 175 | + HasZone: !Not [!Equals [!Ref ParentZoneStack, '']] |
| 176 | +Resources: |
| 177 | + SecretTargetAttachment: |
| 178 | + Condition: HasSecret |
| 179 | + Type: 'AWS::SecretsManager::SecretTargetAttachment' |
| 180 | + Properties: |
| 181 | + TargetId: !Ref DBCluster |
| 182 | + SecretId: {'Fn::ImportValue': !Sub '${ParentSecretStack}-SecretArn'} |
| 183 | + TargetType: 'AWS::RDS::DBCluster' |
| 184 | + RecordSet: |
| 185 | + Condition: HasZone |
| 186 | + Type: 'AWS::Route53::RecordSet' |
| 187 | + Properties: |
| 188 | + HostedZoneId: {'Fn::ImportValue': !Sub '${ParentZoneStack}-HostedZoneId'} |
| 189 | + Name: !Sub |
| 190 | + - '${SubDomainNameWithDot}${HostedZoneName}' |
| 191 | + - SubDomainNameWithDot: !Ref SubDomainNameWithDot |
| 192 | + HostedZoneName: {'Fn::ImportValue': !Sub '${ParentZoneStack}-HostedZoneName'} |
| 193 | + ResourceRecords: |
| 194 | + - !GetAtt 'DBCluster.Endpoint.Address' |
| 195 | + TTL: 60 |
| 196 | + Type: CNAME |
| 197 | + ClusterSecurityGroup: |
| 198 | + Type: 'AWS::EC2::SecurityGroup' |
| 199 | + Properties: |
| 200 | + GroupDescription: !Ref 'AWS::StackName' |
| 201 | + SecurityGroupIngress: |
| 202 | + - IpProtocol: tcp |
| 203 | + FromPort: !Ref DBPort |
| 204 | + ToPort: !Ref DBPort |
| 205 | + SourceSecurityGroupId: {'Fn::ImportValue': !Sub '${ParentClientStack}-ClientSecurityGroup'} |
| 206 | + VpcId: {'Fn::ImportValue': !Sub '${ParentVPCStack}-VPC'} |
| 207 | + ClusterSecurityGroupInSSHBastion: |
| 208 | + Type: 'AWS::EC2::SecurityGroupIngress' |
| 209 | + Condition: HasSSHBastionSecurityGroup |
| 210 | + Properties: |
| 211 | + GroupId: !Ref ClusterSecurityGroup |
| 212 | + IpProtocol: tcp |
| 213 | + FromPort: !Ref DBPort |
| 214 | + ToPort: !Ref DBPort |
| 215 | + SourceSecurityGroupId: {'Fn::ImportValue': !Sub '${ParentSSHBastionStack}-SecurityGroup'} |
| 216 | + DBSubnetGroup: |
| 217 | + Type: 'AWS::RDS::DBSubnetGroup' |
| 218 | + Properties: |
| 219 | + DBSubnetGroupDescription: !Ref 'AWS::StackName' |
| 220 | + SubnetIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SubnetsPrivate'}] |
| 221 | + DBClusterParameterGroup: |
| 222 | + Type: 'AWS::RDS::DBClusterParameterGroup' |
| 223 | + Condition: HasNotDBClusterParameterGroup |
| 224 | + Properties: |
| 225 | + Description: !Ref 'AWS::StackName' |
| 226 | + Family: !FindInMap [EngineVersionMap, !Ref EngineVersion, ClusterParameterGroupFamily] |
| 227 | + Parameters: |
| 228 | + client_encoding: 'UTF8' |
| 229 | + DBParameterGroup: |
| 230 | + Type: 'AWS::RDS::DBParameterGroup' |
| 231 | + Condition: HasNotDBParameterGroup |
| 232 | + Properties: |
| 233 | + Description: !Ref 'AWS::StackName' |
| 234 | + Family: !FindInMap [EngineVersionMap, !Ref EngineVersion, ClusterParameterGroupFamily] |
| 235 | + Parameters: {} |
| 236 | + EnhancedMonitoringRole: |
| 237 | + Type: AWS::IAM::Role |
| 238 | + Properties: |
| 239 | + AssumeRolePolicyDocument: |
| 240 | + Version: 2012-10-17 |
| 241 | + Statement: |
| 242 | + - Sid: AmazonRDSEnhancedMonitoringRole |
| 243 | + Effect: Allow |
| 244 | + Principal: |
| 245 | + Service: monitoring.rds.amazonaws.com |
| 246 | + Action: sts:AssumeRole |
| 247 | + ManagedPolicyArns: |
| 248 | + - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole" |
| 249 | + DBCluster: |
| 250 | + DeletionPolicy: Snapshot # default |
| 251 | + UpdateReplacePolicy: Snapshot |
| 252 | + Type: 'AWS::RDS::DBCluster' |
| 253 | + Properties: |
| 254 | + AvailabilityZones: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-AZList'}] |
| 255 | + BackupRetentionPeriod: !Ref DBBackupRetentionPeriod |
| 256 | + DatabaseName: !If [HasDBSnapshotIdentifier, !Ref 'AWS::NoValue', !Ref DBName] |
| 257 | + CopyTagsToSnapshot: true |
| 258 | + DBClusterParameterGroupName: !If |
| 259 | + - HasDBClusterParameterGroup |
| 260 | + - !Ref DBClusterParameterGroupName |
| 261 | + - !Ref DBClusterParameterGroup |
| 262 | + DBSubnetGroupName: !Ref DBSubnetGroup |
| 263 | + EnableHttpEndpoint: !Ref EnableDataApi |
| 264 | + EnableCloudwatchLogsExports: |
| 265 | + - postgresql |
| 266 | + Engine: aurora-postgresql |
| 267 | + EngineVersion: !Ref EngineVersion |
| 268 | + Port: !Ref DBPort |
| 269 | + KmsKeyId: !If [HasDBSnapshotIdentifier, !Ref 'AWS::NoValue', {'Fn::ImportValue': !Sub '${ParentKmsKeyStack}-KeyArn'}] |
| 270 | + MasterUsername: !If [HasDBSnapshotIdentifier, !Ref 'AWS::NoValue', !Ref DBMasterUsername] |
| 271 | + MasterUserPassword: !If |
| 272 | + - HasDBSnapshotIdentifier |
| 273 | + - !Ref 'AWS::NoValue' |
| 274 | + - !If |
| 275 | + - HasSecret |
| 276 | + - !Join ['', ['{{resolve:secretsmanager:', {'Fn::ImportValue': !Sub '${ParentSecretStack}-SecretArn'}, ':SecretString:password}}']] |
| 277 | + - !Ref DBMasterUserPassword |
| 278 | + # PreferredBackupWindow: !Ref PreferredBackupWindow TODO re-enable as soon as CloudFormation bug ix fixed |
| 279 | + # PreferredMaintenanceWindow: !Ref PreferredMaintenanceWindow TODO re-enable as soon as CloudFormation bug ix fixed |
| 280 | + ServerlessV2ScalingConfiguration: |
| 281 | + MaxCapacity: !Ref MaxCapacity |
| 282 | + MinCapacity: !Ref MinCapacity |
| 283 | + SnapshotIdentifier: !If [HasDBSnapshotIdentifier, !Ref DBSnapshotIdentifier, !Ref 'AWS::NoValue'] |
| 284 | + StorageEncrypted: true |
| 285 | + VpcSecurityGroupIds: |
| 286 | + - !Ref ClusterSecurityGroup |
| 287 | + DBInstanceA: |
| 288 | + Type: AWS::RDS::DBInstance |
| 289 | + Properties: |
| 290 | + AllowMajorVersionUpgrade: false |
| 291 | + AutoMinorVersionUpgrade: true |
| 292 | + CACertificateIdentifier: !Ref CACertificateIdentifier |
| 293 | + DBClusterIdentifier: !Ref DBCluster |
| 294 | + DBInstanceClass: db.serverless |
| 295 | + DBParameterGroupName: !If |
| 296 | + - HasDBParameterGroup |
| 297 | + - !Ref DBParameterGroupName |
| 298 | + - !Ref DBParameterGroup |
| 299 | + DBSubnetGroupName: !Ref DBSubnetGroup |
| 300 | + EnablePerformanceInsights: true |
| 301 | + Engine: aurora-postgresql |
| 302 | + MonitoringInterval: 30 |
| 303 | + MonitoringRoleArn: !GetAtt EnhancedMonitoringRole.Arn |
| 304 | + PerformanceInsightsRetentionPeriod: !Ref PerformanceInsightsRetentionPeriod |
| 305 | + DBInstanceB: |
| 306 | + Type: AWS::RDS::DBInstance |
| 307 | + Properties: |
| 308 | + AllowMajorVersionUpgrade: false |
| 309 | + AutoMinorVersionUpgrade: true |
| 310 | + CACertificateIdentifier: !Ref CACertificateIdentifier |
| 311 | + DBClusterIdentifier: !Ref DBCluster |
| 312 | + DBInstanceClass: db.serverless |
| 313 | + DBParameterGroupName: !If |
| 314 | + - HasDBParameterGroup |
| 315 | + - !Ref DBParameterGroupName |
| 316 | + - !Ref DBParameterGroup |
| 317 | + DBSubnetGroupName: !Ref DBSubnetGroup |
| 318 | + EnablePerformanceInsights: true |
| 319 | + Engine: aurora-postgresql |
| 320 | + MonitoringInterval: 30 |
| 321 | + MonitoringRoleArn: !GetAtt EnhancedMonitoringRole.Arn |
| 322 | + PerformanceInsightsRetentionPeriod: !Ref PerformanceInsightsRetentionPeriod |
| 323 | + DatabaseClusterEventSubscription: |
| 324 | + Condition: HasAlertTopic |
| 325 | + Type: 'AWS::RDS::EventSubscription' |
| 326 | + Properties: |
| 327 | + EventCategories: |
| 328 | + - failover |
| 329 | + - failure |
| 330 | + - maintenance |
| 331 | + SnsTopicArn: {'Fn::ImportValue': !Sub '${ParentAlertStack}-TopicARN'} |
| 332 | + SourceIds: [!Ref DBCluster] |
| 333 | + SourceType: 'db-cluster' |
| 334 | +Outputs: |
| 335 | + TemplateID: |
| 336 | + Description: 'cloudonaut.io template id.' |
| 337 | + Value: 'state/rds-aurora-serverless-postgres' |
| 338 | + TemplateVersion: |
| 339 | + Description: 'cloudonaut.io template version.' |
| 340 | + Value: '__VERSION__' |
| 341 | + StackName: |
| 342 | + Description: 'Stack name.' |
| 343 | + Value: !Sub '${AWS::StackName}' |
| 344 | + ClusterName: |
| 345 | + Description: 'The name of the cluster.' |
| 346 | + Value: !Ref DBCluster |
| 347 | + Export: |
| 348 | + Name: !Sub '${AWS::StackName}-ClusterName' |
| 349 | + DNSName: |
| 350 | + Description: 'The connection endpoint for the DB cluster.' |
| 351 | + Value: !GetAtt 'DBCluster.Endpoint.Address' |
| 352 | + Export: |
| 353 | + Name: !Sub '${AWS::StackName}-DNSName' |
| 354 | + SecurityGroupId: |
| 355 | + Description: 'The security group used to manage access to RDS Aurora Serverless Postgres.' |
| 356 | + Value: !Ref ClusterSecurityGroup |
| 357 | + Export: |
| 358 | + Name: !Sub '${AWS::StackName}-SecurityGroupId' |
| 359 | + EndpointAddress: |
| 360 | + Value: !GetAtt 'DBCluster.Endpoint.Address' |
| 361 | + Export: |
| 362 | + Name: !Sub '${AWS::StackName}-EndpointAddress' |
| 363 | + ReadEndpointAddress: |
| 364 | + Value: !GetAtt 'DBCluster.ReadEndpoint.Address' |
| 365 | + Export: |
| 366 | + Name: !Sub '${AWS::StackName}-ReadEndpointAddress' |
| 367 | + EndpointPort: |
| 368 | + Value: !GetAtt 'DBCluster.Endpoint.Port' |
| 369 | + Export: |
| 370 | + Name: !Sub '${AWS::StackName}-EndpointPort' |
0 commit comments